Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| - | 11394324 | 1941 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0xabfe46e50d7a72e17688b44ce4f8b95545020560
Contract Name:
Feed
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2020-03-01
*/
pragma solidity 0.5.16;
/// @title EventMetadata
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice This module emits metadata blob as an event.
contract EventMetadata {
event MetadataSet(bytes metadata);
// state functions
/// @notice Emit a metadata blob.
/// @param metadata data blob of any format.
function _setMetadata(bytes memory metadata) internal {
emit MetadataSet(metadata);
}
}
/// @title Operated
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
contract Operated {
address private _operator;
event OperatorUpdated(address operator);
// state functions
function _setOperator(address operator) internal {
// can only be called when operator is null
require(_operator == address(0), "operator already set");
// cannot set to address 0
require(operator != address(0), "cannot set operator to address 0");
// set operator in storage
_operator = operator;
// emit event
emit OperatorUpdated(operator);
}
function _transferOperator(address operator) internal {
// requires existing operator
require(_operator != address(0), "only when operator set");
// cannot set to address 0
require(operator != address(0), "cannot set operator to address 0");
// set operator in storage
_operator = operator;
// emit event
emit OperatorUpdated(operator);
}
function _renounceOperator() internal {
// requires existing operator
require(_operator != address(0), "only when operator set");
// set operator in storage
_operator = address(0);
// emit event
emit OperatorUpdated(address(0));
}
// view functions
function getOperator() public view returns (address operator) {
return _operator;
}
function isOperator(address caller) internal view returns (bool ok) {
return caller == _operator;
}
}
/// @title ProofHashes
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
contract ProofHashes {
event HashSubmitted(bytes32 hash);
// state functions
function _submitHash(bytes32 hash) internal {
// emit event
emit HashSubmitted(hash);
}
}
/// @title iFactory
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
interface iFactory {
event InstanceCreated(address indexed instance, address indexed creator, bytes callData);
function create(bytes calldata callData) external returns (address instance);
function createSalty(bytes calldata callData, bytes32 salt) external returns (address instance);
function getInitSelector() external view returns (bytes4 initSelector);
function getInstanceRegistry() external view returns (address instanceRegistry);
function getTemplate() external view returns (address template);
function getSaltyInstance(address creator, bytes calldata callData, bytes32 salt) external view returns (address instance, bool validity);
function getNextNonceInstance(address creator, bytes calldata callData) external view returns (address instance);
function getInstanceCreator(address instance) external view returns (address creator);
function getInstanceType() external view returns (bytes4 instanceType);
function getInstanceCount() external view returns (uint256 count);
function getInstance(uint256 index) external view returns (address instance);
function getInstances() external view returns (address[] memory instances);
function getPaginatedInstances(uint256 startIndex, uint256 endIndex) external view returns (address[] memory instances);
}
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
contract UniswapExchangeInterface {
// Address of ERC20 token sold on this exchange
function tokenAddress() external view returns (address token);
// Address of Uniswap Factory
function factoryAddress() external view returns (address factory);
// Provide Liquidity
function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256);
function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256);
// Get Prices
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
// Trade ETH to ERC20
function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought);
function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought);
function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold);
function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256 eth_sold);
// Trade ERC20 to ETH
function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought);
function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256 eth_bought);
function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256 tokens_sold);
function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256 tokens_sold);
// Trade ERC20 to ERC20
function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256 tokens_bought);
function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_bought);
function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256 tokens_sold);
function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_sold);
// Trade ERC20 to Custom Pool
function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256 tokens_bought);
function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_bought);
function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256 tokens_sold);
function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_sold);
// ERC20 comaptibility for liquidity tokens
bytes32 public name;
bytes32 public symbol;
uint256 public decimals;
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
function balanceOf(address _owner) external view returns (uint256);
function totalSupply() external view returns (uint256);
// Never use
function setup(address token_addr) external;
}
/// @title iNMR
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
contract iNMR {
// ERC20
function totalSupply() external returns (uint256);
function balanceOf(address _owner) external returns (uint256);
function allowance(address _owner, address _spender) external returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool ok);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool ok);
function approve(address _spender, uint256 _value) external returns (bool ok);
function changeApproval(address _spender, uint256 _oldValue, uint256 _newValue) external returns (bool ok);
/// @dev Behavior has changed to match OpenZeppelin's `ERC20Burnable.burn(uint256 amount)`
/// @dev Destoys `amount` tokens from `msg.sender`, reducing the total supply.
///
/// Emits a `Transfer` event with `to` set to the zero address.
/// Requirements:
/// - `account` must have at least `amount` tokens.
function mint(uint256 _value) external returns (bool ok);
/// @dev Behavior has changed to match OpenZeppelin's `ERC20Burnable.burnFrom(address account, uint256 amount)`
/// @dev Destoys `amount` tokens from `account`.`amount` is then deducted
/// from the caller's allowance.
///
/// Emits an `Approval` event indicating the updated allowance.
/// Emits a `Transfer` event with `to` set to the zero address.
///
/// Requirements:
/// - `account` must have at least `amount` tokens.
/// - `account` must have approved `msg.sender` with allowance of at least `amount` tokens.
function numeraiTransfer(address _to, uint256 _value) external returns (bool ok);
}
/// @title Template
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice This module is imported by all template contracts to implement core functionality associated with the factories.
contract Template {
address private _factory;
// modifiers
/// @notice Modifier which only allows to be `DELEGATECALL`ed from within a constructor on initialization of the contract.
modifier initializeTemplate() {
// set factory
_factory = msg.sender;
// only allow function to be `DELEGATECALL`ed from within a constructor.
uint32 codeSize;
assembly { codeSize := extcodesize(address) }
require(codeSize == 0, "must be called within contract constructor");
_;
}
// view functions
/// @notice Get the address that created this clone.
/// Note, this cannot be trusted because it is possible to frontrun the create function and become the creator.
/// @return creator address that created this clone.
function getCreator() public view returns (address creator) {
// iFactory(...) would revert if _factory address is not actually a factory contract
return iFactory(_factory).getInstanceCreator(address(this));
}
/// @notice Validate if address matches the stored creator.
/// @param caller address to validate.
/// @return validity bool true if matching address.
function isCreator(address caller) internal view returns (bool validity) {
return (caller == getCreator());
}
/// @notice Get the address of the factory for this clone.
/// @return factory address of the factory.
function getFactory() public view returns (address factory) {
return _factory;
}
}
/// @title BurnNMR
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice This module simplifies calling NMR burn functions using regular openzeppelin ERC20Burnable interface and revert on failure.
/// This helper is required given the non-standard implementation of the NMR burn functions: https://github.com/numerai/contract
contract BurnNMR {
// address of the token
address private constant _NMRToken = address(0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671);
// uniswap exchange of the token
address private constant _NMRExchange = address(0x2Bf5A5bA29E60682fC56B2Fcf9cE07Bef4F6196f);
/// @notice Burns a specific amount of NMR from this contract.
/// @param value uint256 The amount of NMR (18 decimals) to be burned.
function _burn(uint256 value) internal {
require(iNMR(_NMRToken).mint(value), "nmr burn failed");
}
/// @notice Burns a specific amount of NMR from the target address and decrements allowance.
/// @param from address The account whose tokens will be burned.
/// @param value uint256 The amount of NMR (18 decimals) to be burned.
function _burnFrom(address from, uint256 value) internal {
require(iNMR(_NMRToken).numeraiTransfer(from, value), "nmr burnFrom failed");
}
/// @notice Get the NMR token address.
/// @return token address The NMR token address.
function getTokenAddress() internal pure returns (address token) {
token = _NMRToken;
}
/// @notice Get the NMR Uniswap exchange address.
/// @return token address The NMR Uniswap exchange address.
function getExchangeAddress() internal pure returns (address exchange) {
exchange = _NMRExchange;
}
}
/// @title BurnDAI
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice This module allows for burning DAI tokens by exchanging them for NMR on uniswap and burning the NMR.
contract BurnDAI is BurnNMR {
// address of the token
address private constant _DAIToken = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);
// uniswap exchange of the token
address private constant _DAIExchange = address(0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667);
/// @notice Burns a specific amount of DAI from the target address and decrements allowance.
/// @dev This implementation has no frontrunning protection.
/// @param from address The account whose tokens will be burned.
/// @param value uint256 The amount of DAI (18 decimals) to be burned.
function _burnFrom(address from, uint256 value) internal {
// transfer dai to this contract
IERC20(_DAIToken).transferFrom(from, address(this), value);
// butn nmr
_burn(value);
}
/// @notice Burns a specific amount of DAI from this contract.
/// @dev This implementation has no frontrunning protection.
/// @param value uint256 The amount of DAI (18 decimals) to be burned.
function _burn(uint256 value) internal {
// approve uniswap for token transfer
IERC20(_DAIToken).approve(_DAIExchange, value);
// swap dai for nmr
uint256 tokens_sold = value;
(uint256 min_tokens_bought, uint256 min_eth_bought) = getExpectedSwapAmount(tokens_sold);
uint256 deadline = now;
uint256 tokens_bought = UniswapExchangeInterface(_DAIExchange).tokenToTokenSwapInput(
tokens_sold,
min_tokens_bought,
min_eth_bought,
deadline,
BurnNMR.getTokenAddress()
);
// burn nmr
BurnNMR._burn(tokens_bought);
}
/// @notice Get the amount of NMR and ETH required to sell a given amount of DAI.
/// @param amountDAI uint256 The amount of DAI (18 decimals) to sell.
/// @param amountNMR uint256 The amount of NMR (18 decimals) required.
/// @param amountETH uint256 The amount of ETH (18 decimals) required.
function getExpectedSwapAmount(uint256 amountDAI) internal view returns (uint256 amountNMR, uint256 amountETH) {
amountETH = UniswapExchangeInterface(_DAIExchange).getTokenToEthInputPrice(amountDAI);
amountNMR = UniswapExchangeInterface(BurnNMR.getExchangeAddress()).getEthToTokenInputPrice(amountETH);
return (amountNMR, amountETH);
}
/// @notice Get the DAI token address.
/// @return token address The DAI token address.
function getTokenAddress() internal pure returns (address token) {
token = _DAIToken;
}
/// @notice Get the DAI Uniswap exchange address.
/// @return token address The DAI Uniswap exchange address.
function getExchangeAddress() internal pure returns (address exchange) {
exchange = _DAIExchange;
}
}
/// @title TokenManager
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice This module provides a standard interface for interacting with supported ERC20 tokens.
contract TokenManager is BurnDAI {
enum Tokens { NaN, NMR, DAI }
/// @notice Get the address of the given token ID.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @return tokenAddress address of the ERC20 token.
function getTokenAddress(Tokens tokenID) public pure returns (address tokenAddress) {
if (tokenID == Tokens.DAI)
return BurnDAI.getTokenAddress();
if (tokenID == Tokens.NMR)
return BurnNMR.getTokenAddress();
return address(0);
}
/// @notice Get the address of the uniswap exchange for given token ID.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @return exchangeAddress address of the uniswap exchange.
function getExchangeAddress(Tokens tokenID) public pure returns (address exchangeAddress) {
if (tokenID == Tokens.DAI)
return BurnDAI.getExchangeAddress();
if (tokenID == Tokens.NMR)
return BurnNMR.getExchangeAddress();
return address(0);
}
modifier onlyValidTokenID(Tokens tokenID) {
require(isValidTokenID(tokenID), 'invalid tokenID');
_;
}
/// @notice Validate the token ID is a supported token.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @return validity bool true if the token is supported.
function isValidTokenID(Tokens tokenID) internal pure returns (bool validity) {
return tokenID == Tokens.NMR || tokenID == Tokens.DAI;
}
/// @notice ERC20 ransfer.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param to address of the recipient.
/// @param value uint256 amount of tokens.
function _transfer(Tokens tokenID, address to, uint256 value) internal onlyValidTokenID(tokenID) {
require(IERC20(getTokenAddress(tokenID)).transfer(to, value), 'token transfer failed');
}
/// @notice ERC20 TransferFrom
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param from address to spend from.
/// @param to address of the recipient.
/// @param value uint256 amount of tokens.
function _transferFrom(Tokens tokenID, address from, address to, uint256 value) internal onlyValidTokenID(tokenID) {
require(IERC20(getTokenAddress(tokenID)).transferFrom(from, to, value), 'token transfer failed');
}
/// @notice ERC20 Burn
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param value uint256 amount of tokens.
function _burn(Tokens tokenID, uint256 value) internal onlyValidTokenID(tokenID) {
if (tokenID == Tokens.DAI) {
BurnDAI._burn(value);
} else if (tokenID == Tokens.NMR) {
BurnNMR._burn(value);
}
}
/// @notice ERC20 BurnFrom
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param from address to burn from.
/// @param value uint256 amount of tokens.
function _burnFrom(Tokens tokenID, address from, uint256 value) internal onlyValidTokenID(tokenID) {
if (tokenID == Tokens.DAI) {
BurnDAI._burnFrom(from, value);
} else if (tokenID == Tokens.NMR) {
BurnNMR._burnFrom(from, value);
}
}
/// @notice ERC20 Approve
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param spender address of the spender.
/// @param value uint256 amount of tokens.
function _approve(Tokens tokenID, address spender, uint256 value) internal onlyValidTokenID(tokenID) {
if (tokenID == Tokens.DAI) {
require(IERC20(BurnDAI.getTokenAddress()).approve(spender, value), 'token approval failed');
} else if (tokenID == Tokens.NMR) {
address nmr = BurnNMR.getTokenAddress();
uint256 currentAllowance = IERC20(nmr).allowance(msg.sender, spender);
require(iNMR(nmr).changeApproval(spender, currentAllowance, value), 'token approval failed');
}
}
/// @notice ERC20 TotalSupply
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @return value uint256 amount of tokens.
function totalSupply(Tokens tokenID) internal view onlyValidTokenID(tokenID) returns (uint256 value) {
return IERC20(getTokenAddress(tokenID)).totalSupply();
}
/// @notice ERC20 BalanceOf
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param who address of the owner.
/// @return value uint256 amount of tokens.
function balanceOf(Tokens tokenID, address who) internal view onlyValidTokenID(tokenID) returns (uint256 value) {
return IERC20(getTokenAddress(tokenID)).balanceOf(who);
}
/// @notice ERC20 Allowance
/// @param tokenID TokenManager.Tokens ID of the ERC20 token.
/// @param owner address of the owner.
/// @param spender address of the spender.
/// @return value uint256 amount of tokens.
function allowance(Tokens tokenID, address owner, address spender) internal view onlyValidTokenID(tokenID) returns (uint256 value) {
return IERC20(getTokenAddress(tokenID)).allowance(owner, spender);
}
}
/// @title Deposit
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @dev State Machine: https://github.com/erasureprotocol/erasure-protocol/blob/release/v1.3.x/docs/state-machines/modules/Deposit.png
/// @notice This module allows for tracking user deposits for fungible tokens.
contract Deposit {
using SafeMath for uint256;
mapping (uint256 => mapping (address => uint256)) private _deposit;
event DepositIncreased(TokenManager.Tokens tokenID, address user, uint256 amount, uint256 newDeposit);
event DepositDecreased(TokenManager.Tokens tokenID, address user, uint256 amount, uint256 newDeposit);
/// @notice Increase the deposit of a user.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param user address of the user.
/// @param amountToAdd uint256 amount by which to increase the deposit.
/// @return newDeposit uint256 amount of the updated deposit.
function _increaseDeposit(TokenManager.Tokens tokenID, address user, uint256 amountToAdd) internal returns (uint256 newDeposit) {
// calculate new deposit amount
newDeposit = _deposit[uint256(tokenID)][user].add(amountToAdd);
// set new stake to storage
_deposit[uint256(tokenID)][user] = newDeposit;
// emit event
emit DepositIncreased(tokenID, user, amountToAdd, newDeposit);
// return
return newDeposit;
}
/// @notice Decrease the deposit of a user.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param user address of the user.
/// @param amountToRemove uint256 amount by which to decrease the deposit.
/// @return newDeposit uint256 amount of the updated deposit.
function _decreaseDeposit(TokenManager.Tokens tokenID, address user, uint256 amountToRemove) internal returns (uint256 newDeposit) {
// get current deposit
uint256 currentDeposit = _deposit[uint256(tokenID)][user];
// check if sufficient deposit
require(currentDeposit >= amountToRemove, "insufficient deposit to remove");
// calculate new deposit amount
newDeposit = currentDeposit.sub(amountToRemove);
// set new stake to storage
_deposit[uint256(tokenID)][user] = newDeposit;
// emit event
emit DepositDecreased(tokenID, user, amountToRemove, newDeposit);
// return
return newDeposit;
}
/// @notice Set the deposit of a user to zero.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param user address of the user.
/// @return amountRemoved uint256 amount removed from deposit.
function _clearDeposit(TokenManager.Tokens tokenID, address user) internal returns (uint256 amountRemoved) {
// get current deposit
uint256 currentDeposit = _deposit[uint256(tokenID)][user];
// remove deposit
_decreaseDeposit(tokenID, user, currentDeposit);
// return
return currentDeposit;
}
// view functions
/// @notice Get the current deposit of a user.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param user address of the user.
/// @return deposit uint256 current amount of the deposit.
function getDeposit(TokenManager.Tokens tokenID, address user) internal view returns (uint256 deposit) {
return _deposit[uint256(tokenID)][user];
}
}
/// @title Staking
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @dev State Machine: https://github.com/erasureprotocol/erasure-protocol/blob/release/v1.3.x/docs/state-machines/modules/Staking.png
/// @notice This module wraps the Deposit functions and the ERC20 functions to provide combined actions.
contract Staking is Deposit, TokenManager {
using SafeMath for uint256;
event StakeBurned(TokenManager.Tokens tokenID, address staker, uint256 amount);
/// @notice Transfer and deposit ERC20 tokens to this contract.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param staker Address of the staker who owns the stake.
/// @param funder Address of the funder from whom the tokens are transfered.
/// @param amountToAdd uint256 amount of tokens (18 decimals) to be added to the stake.
/// @return newStake uint256 amount of tokens (18 decimals) remaining in the stake.
function _addStake(TokenManager.Tokens tokenID, address staker, address funder, uint256 amountToAdd) internal returns (uint256 newStake) {
// update deposit
newStake = Deposit._increaseDeposit(tokenID, staker, amountToAdd);
// transfer the stake amount
TokenManager._transferFrom(tokenID, funder, address(this), amountToAdd);
// explicit return
return newStake;
}
/// @notice Withdraw some deposited stake and transfer to recipient.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param staker Address of the staker who owns the stake.
/// @param recipient Address of the recipient who receives the tokens.
/// @param amountToTake uint256 amount of tokens (18 decimals) to be remove from the stake.
/// @return newStake uint256 amount of tokens (18 decimals) remaining in the stake.
function _takeStake(TokenManager.Tokens tokenID, address staker, address recipient, uint256 amountToTake) internal returns (uint256 newStake) {
// update deposit
newStake = Deposit._decreaseDeposit(tokenID, staker, amountToTake);
// transfer the stake amount
TokenManager._transfer(tokenID, recipient, amountToTake);
// explicit return
return newStake;
}
/// @notice Withdraw all deposited stake and transfer to recipient.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param staker Address of the staker who owns the stake.
/// @param recipient Address of the recipient who receives the tokens.
/// @return amountTaken uint256 amount of tokens (18 decimals) taken from the stake.
function _takeFullStake(TokenManager.Tokens tokenID, address staker, address recipient) internal returns (uint256 amountTaken) {
// get deposit
uint256 currentDeposit = Deposit.getDeposit(tokenID, staker);
// take full stake
_takeStake(tokenID, staker, recipient, currentDeposit);
// return
return currentDeposit;
}
/// @notice Burn some deposited stake.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param staker Address of the staker who owns the stake.
/// @param amountToBurn uint256 amount of tokens (18 decimals) to be burn from the stake.
/// @return newStake uint256 amount of tokens (18 decimals) remaining in the stake.
function _burnStake(TokenManager.Tokens tokenID, address staker, uint256 amountToBurn) internal returns (uint256 newStake) {
// update deposit
uint256 newDeposit = Deposit._decreaseDeposit(tokenID, staker, amountToBurn);
// burn the stake amount
TokenManager._burn(tokenID, amountToBurn);
// emit event
emit StakeBurned(tokenID, staker, amountToBurn);
// return
return newDeposit;
}
/// @notice Burn all deposited stake.
/// @param tokenID TokenManager.Tokens ID of the ERC20 token. This ID must be one of the IDs supported by TokenManager.
/// @param staker Address of the staker who owns the stake.
/// @return amountBurned uint256 amount of tokens (18 decimals) taken from the stake.
function _burnFullStake(TokenManager.Tokens tokenID, address staker) internal returns (uint256 amountBurned) {
// get deposit
uint256 currentDeposit = Deposit.getDeposit(tokenID, staker);
// burn full stake
_burnStake(tokenID, staker, currentDeposit);
// return
return currentDeposit;
}
}
/// @title Feed
/// @author Stephane Gosselin (@thegostep) for Numerai Inc
/// @dev Security contact: security@numer.ai
/// @dev Version: 1.3.0
/// @notice A Feed allows for the creator to build a track record of timestamped submissions and deposit a stake to signal legitimacy.
contract Feed is Staking, ProofHashes, Operated, EventMetadata, Template {
event Initialized(address operator, bytes metadata);
/// @notice Constructor
/// @dev Access Control: only factory
/// State Machine: before all
/// @param operator Address of the operator that overrides access control
/// @param metadata Data (any format) to emit as event on initialization
function initialize(
address operator,
bytes memory metadata
) public initializeTemplate() {
// set operator
if (operator != address(0)) {
Operated._setOperator(operator);
}
// set metadata
if (metadata.length != 0) {
EventMetadata._setMetadata(metadata);
}
// log initialization params
emit Initialized(operator, metadata);
}
// state functions
/// @notice Submit proofhash to add to feed
/// @dev Access Control: creator OR operator
/// State Machine: anytime
/// @param proofHash Proofhash (bytes32) sha256 hash of timestampled data
function submitHash(bytes32 proofHash) public {
// only operator or creator
require(Template.isCreator(msg.sender) || Operated.isOperator(msg.sender), "only operator or creator");
// submit proofHash
ProofHashes._submitHash(proofHash);
}
/// @notice Deposit one of the supported ERC20 token.
/// - This deposit can be withdrawn at any time by the owner of the feed.
/// - This requires the caller to do ERC20 approval for this contract for `amountToAdd`.
/// @dev Access Control: creator OR operator
/// State Machine: anytime
/// @param tokenID TokenManager.Tokens id of the ERC20 token.
/// @param amountToAdd uint256 amount of ERC20 tokens (18 decimals) to add.
function depositStake(TokenManager.Tokens tokenID, uint256 amountToAdd) public returns (uint256 newStake) {
// only operator or creator
require(Template.isCreator(msg.sender) || Operated.isOperator(msg.sender), "only operator or creator");
// transfer and add tokens to stake
return Staking._addStake(tokenID, Template.getCreator(), msg.sender, amountToAdd);
}
/// @notice Withdraw one of the supported ERC20 token.
/// @dev Access Control: creator OR operator
/// State Machine: anytime
/// @param tokenID TokenManager.Tokens id of the ERC20 token.
/// @param amountToRemove uint256 amount of ERC20 tokens (18 decimals) to add.
function withdrawStake(TokenManager.Tokens tokenID, uint256 amountToRemove) public returns (uint256 newStake) {
// only operator or creator
require(Template.isCreator(msg.sender) || Operated.isOperator(msg.sender), "only operator or creator");
// transfer and remove tokens from stake
return Staking._takeStake(tokenID, Template.getCreator(), Template.getCreator(), amountToRemove);
}
/// @notice Emit metadata event
/// @dev Access Control: creator OR operator
/// State Machine: anytime
/// @param metadata Data (any format) to emit as event
function setMetadata(bytes memory metadata) public {
// only operator or creator
require(Template.isCreator(msg.sender) || Operated.isOperator(msg.sender), "only operator or creator");
// set metadata
EventMetadata._setMetadata(metadata);
}
/// @notice Called by the operator to transfer control to new operator
/// @dev Access Control: operator
/// State Machine: anytime
/// @param operator Address of the new operator
function transferOperator(address operator) public {
// restrict access
require(Operated.isOperator(msg.sender), "only operator");
// transfer operator
Operated._transferOperator(operator);
}
/// @notice Called by the operator to renounce control
/// @dev Access Control: operator
/// State Machine: anytime
function renounceOperator() public {
// restrict access
require(Operated.isOperator(msg.sender), "only operator");
// renounce operator
Operated._renounceOperator();
}
/// @notice Get the current stake for a given ERC20 token.
/// @dev Access Control: creator OR operator
/// State Machine: anytime
/// @param tokenID TokenManager.Tokens id of the ERC20 token.
function getStake(TokenManager.Tokens tokenID) public view returns (uint256 stake) {
return Deposit.getDeposit(tokenID, Template.getCreator());
}
}Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDeposit","type":"uint256"}],"name":"DepositDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDeposit","type":"uint256"}],"name":"DepositIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"MetadataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeBurned","type":"event"},{"constant":false,"inputs":[{"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"},{"internalType":"uint256","name":"amountToAdd","type":"uint256"}],"name":"depositStake","outputs":[{"internalType":"uint256","name":"newStake","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getCreator","outputs":[{"internalType":"address","name":"creator","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"}],"name":"getExchangeAddress","outputs":[{"internalType":"address","name":"exchangeAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getFactory","outputs":[{"internalType":"address","name":"factory","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOperator","outputs":[{"internalType":"address","name":"operator","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"}],"name":"getStake","outputs":[{"internalType":"uint256","name":"stake","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"}],"name":"getTokenAddress","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"setMetadata","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"proofHash","type":"bytes32"}],"name":"submitHash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"transferOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"enum TokenManager.Tokens","name":"tokenID","type":"uint8"},{"internalType":"uint256","name":"amountToRemove","type":"uint256"}],"name":"withdrawStake","outputs":[{"internalType":"uint256","name":"newStake","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.