Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 15 from a total of 15 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Stake | 14171563 | 1037 days ago | IN | 0 ETH | 0.00808099 | ||||
Withdraw Stake | 14164896 | 1038 days ago | IN | 0 ETH | 0.01207541 | ||||
Withdraw Stake | 14067964 | 1053 days ago | IN | 0 ETH | 0.03088918 | ||||
Withdraw Stake | 13946715 | 1072 days ago | IN | 0 ETH | 0.02539436 | ||||
Stake DAI | 13255458 | 1180 days ago | IN | 0 ETH | 0.00681081 | ||||
Stake DAI | 11548852 | 1444 days ago | IN | 0 ETH | 0.01612396 | ||||
Stake DAI | 11482324 | 1454 days ago | IN | 0 ETH | 0.01208835 | ||||
Withdraw Stake | 11286824 | 1484 days ago | IN | 0 ETH | 0.00530548 | ||||
Stake DAI | 11284739 | 1485 days ago | IN | 0 ETH | 0.01198251 | ||||
Stake DAI | 11264410 | 1488 days ago | IN | 0 ETH | 0.00984335 | ||||
Stake DAI | 11264398 | 1488 days ago | IN | 0 ETH | 0.00984335 | ||||
Stake DAI | 10878285 | 1547 days ago | IN | 0 ETH | 0.2129268 | ||||
Stake DAI | 10819605 | 1556 days ago | IN | 0 ETH | 0.02922944 | ||||
Stake DAI | 10580396 | 1593 days ago | IN | 0 ETH | 0.02008905 | ||||
Start | 10575767 | 1594 days ago | IN | 0 ETH | 0.00870636 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
SimpleDAIStaking
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-08-02 */ /** Support UBI! https://github.com/GoodDollar/GoodContracts */ pragma solidity >0.5.4; /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on 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-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev give an account access to this role */ function add(Role storage role, address account) internal { require(account != address(0)); require(!has(role, account)); role.bearer[account] = true; } /** * @dev remove an account's access to this role */ function remove(Role storage role, address account) internal { require(account != address(0)); require(has(role, account)); role.bearer[account] = false; } /** * @dev check if an account has this role * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0)); return role.bearer[account]; } } contract PauserRole { using Roles for Roles.Role; event PauserAdded(address indexed account); event PauserRemoved(address indexed account); Roles.Role private _pausers; constructor () internal { _addPauser(msg.sender); } modifier onlyPauser() { require(isPauser(msg.sender)); _; } function isPauser(address account) public view returns (bool) { return _pausers.has(account); } function addPauser(address account) public onlyPauser { _addPauser(account); } function renouncePauser() public { _removePauser(msg.sender); } function _addPauser(address account) internal { _pausers.add(account); emit PauserAdded(account); } function _removePauser(address account) internal { _pausers.remove(account); emit PauserRemoved(account); } } /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. */ contract Pausable is PauserRole { event Paused(address account); event Unpaused(address account); bool private _paused; constructor () internal { _paused = false; } /** * @return true if the contract is paused, false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!_paused); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(_paused); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() public onlyPauser whenNotPaused { _paused = true; emit Paused(msg.sender); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() public onlyPauser whenPaused { _paused = false; emit Unpaused(msg.sender); } } /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface IERC20 { function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md * Originally based on code by FirstBlood: * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol * * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for * all accounts just by listening to said events. Note that this isn't required by the specification, and other * compliant implementations may not do it. */ contract ERC20 is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowed; uint256 private _totalSupply; /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev Gets the balance of the specified address. * @param owner The address to query the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param owner address The address which owns the funds. * @param spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * 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 * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @dev Transfer tokens from one address to another. * Note that while this function emits an Approval event, this is not required as per the specification, * and other compliant implementations may not emit the event. * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value); _transfer(from, to, value); emit Approval(from, msg.sender, _allowed[from][msg.sender]); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Transfer token for a specified addresses * @param from The address to transfer from. * @param to The address to transfer to. * @param value The amount to be transferred. */ function _transfer(address from, address to, uint256 value) internal { require(to != address(0)); _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Internal function that mints an amount of the token and assigns it to * an account. This encapsulates the modification of balances such that the * proper events are emitted. * @param account The account that will receive the created tokens. * @param value The amount that will be created. */ function _mint(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.add(value); _balances[account] = _balances[account].add(value); emit Transfer(address(0), account, value); } /** * @dev Internal function that burns an amount of the token of a given * account. * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Internal function that burns an amount of the token of a given * account, deducting from the sender's allowance for said account. Uses the * internal burn function. * Emits an Approval event (reflecting the reduced allowance). * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burnFrom(address account, uint256 value) internal { _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value); _burn(account, value); emit Approval(account, msg.sender, _allowed[account][msg.sender]); } } /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } /** * @title Reputation system * @dev A DAO has Reputation System which allows peers to rate other peers in order to build trust . * A reputation is use to assign influence measure to a DAO'S peers. * Reputation is similar to regular tokens but with one crucial difference: It is non-transferable. * The Reputation contract maintain a map of address to reputation value. * It provides an onlyOwner functions to mint and burn reputation _to (or _from) a specific address. */ contract Reputation is Ownable { uint8 public decimals = 18; //Number of decimals of the smallest unit // Event indicating minting of reputation to an address. event Mint(address indexed _to, uint256 _amount); // Event indicating burning of reputation for an address. event Burn(address indexed _from, uint256 _amount); /// @dev `Checkpoint` is the structure that attaches a block number to a /// given value, the block number attached is the one that last changed the /// value struct Checkpoint { // `fromBlock` is the block number that the value was generated from uint128 fromBlock; // `value` is the amount of reputation at a specific block number uint128 value; } // `balances` is the map that tracks the balance of each address, in this // contract when the balance changes the block number that the change // occurred is also included in the map mapping (address => Checkpoint[]) balances; // Tracks the history of the `totalSupply` of the reputation Checkpoint[] totalSupplyHistory; /// @notice Constructor to create a Reputation constructor( ) public { } /// @dev This function makes it easy to get the total number of reputation /// @return The total number of reputation function totalSupply() public view returns (uint256) { return totalSupplyAt(block.number); } //////////////// // Query balance and totalSupply in History //////////////// /** * @dev return the reputation amount of a given owner * @param _owner an address of the owner which we want to get his reputation */ function balanceOf(address _owner) public view returns (uint256 balance) { return balanceOfAt(_owner, block.number); } /// @dev Queries the balance of `_owner` at a specific `_blockNumber` /// @param _owner The address from which the balance will be retrieved /// @param _blockNumber The block number when the balance is queried /// @return The balance at `_blockNumber` function balanceOfAt(address _owner, uint256 _blockNumber) public view returns (uint256) { if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) { return 0; // This will return the expected balance during normal situations } else { return getValueAt(balances[_owner], _blockNumber); } } /// @notice Total amount of reputation at a specific `_blockNumber`. /// @param _blockNumber The block number when the totalSupply is queried /// @return The total amount of reputation at `_blockNumber` function totalSupplyAt(uint256 _blockNumber) public view returns(uint256) { if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) { return 0; // This will return the expected totalSupply during normal situations } else { return getValueAt(totalSupplyHistory, _blockNumber); } } /// @notice Generates `_amount` reputation that are assigned to `_owner` /// @param _user The address that will be assigned the new reputation /// @param _amount The quantity of reputation generated /// @return True if the reputation are generated correctly function mint(address _user, uint256 _amount) public onlyOwner returns (bool) { uint256 curTotalSupply = totalSupply(); require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow uint256 previousBalanceTo = balanceOf(_user); require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount); updateValueAtNow(balances[_user], previousBalanceTo + _amount); emit Mint(_user, _amount); return true; } /// @notice Burns `_amount` reputation from `_owner` /// @param _user The address that will lose the reputation /// @param _amount The quantity of reputation to burn /// @return True if the reputation are burned correctly function burn(address _user, uint256 _amount) public onlyOwner returns (bool) { uint256 curTotalSupply = totalSupply(); uint256 amountBurned = _amount; uint256 previousBalanceFrom = balanceOf(_user); if (previousBalanceFrom < amountBurned) { amountBurned = previousBalanceFrom; } updateValueAtNow(totalSupplyHistory, curTotalSupply - amountBurned); updateValueAtNow(balances[_user], previousBalanceFrom - amountBurned); emit Burn(_user, amountBurned); return true; } //////////////// // Internal helper functions to query and set a value in a snapshot array //////////////// /// @dev `getValueAt` retrieves the number of reputation at a given block number /// @param checkpoints The history of values being queried /// @param _block The block number to retrieve the value at /// @return The number of reputation being queried function getValueAt(Checkpoint[] storage checkpoints, uint256 _block) internal view returns (uint256) { if (checkpoints.length == 0) { return 0; } // Shortcut for the actual value if (_block >= checkpoints[checkpoints.length-1].fromBlock) { return checkpoints[checkpoints.length-1].value; } if (_block < checkpoints[0].fromBlock) { return 0; } // Binary search of the value in the array uint256 min = 0; uint256 max = checkpoints.length-1; while (max > min) { uint256 mid = (max + min + 1) / 2; if (checkpoints[mid].fromBlock<=_block) { min = mid; } else { max = mid-1; } } return checkpoints[min].value; } /// @dev `updateValueAtNow` used to update the `balances` map and the /// `totalSupplyHistory` /// @param checkpoints The history of data being updated /// @param _value The new number of reputation function updateValueAtNow(Checkpoint[] storage checkpoints, uint256 _value) internal { require(uint128(_value) == _value); //check value is in the 128 bits bounderies if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) { Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++]; newCheckPoint.fromBlock = uint128(block.number); newCheckPoint.value = uint128(_value); } else { Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1]; oldCheckPoint.value = uint128(_value); } } } /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ contract ERC20Burnable is ERC20 { /** * @dev Burns a specific amount of tokens. * @param value The amount of token to be burned. */ function burn(uint256 value) public { _burn(msg.sender, value); } /** * @dev Burns a specific amount of tokens from the target address and decrements allowance * @param from address The address which you want to send tokens from * @param value uint256 The amount of token to be burned */ function burnFrom(address from, uint256 value) public { _burnFrom(from, value); } } /** * @title DAOToken, base on zeppelin contract. * @dev ERC20 compatible token. It is a mintable, burnable token. */ contract DAOToken is ERC20, ERC20Burnable, Ownable { string public name; string public symbol; // solhint-disable-next-line const-name-snakecase uint8 public constant decimals = 18; uint256 public cap; /** * @dev Constructor * @param _name - token name * @param _symbol - token symbol * @param _cap - token cap - 0 value means no cap */ constructor(string memory _name, string memory _symbol, uint256 _cap) public { name = _name; symbol = _symbol; cap = _cap; } /** * @dev Function to mint tokens * @param _to The address that will receive the minted tokens. * @param _amount The amount of tokens to mint. */ function mint(address _to, uint256 _amount) public onlyOwner returns (bool) { if (cap > 0) require(totalSupply().add(_amount) <= cap); _mint(_to, _amount); return true; } } /** * Utility library of inline functions on addresses */ library Address { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } /* SafeERC20 by daostack. The code is based on a fix by SECBIT Team. USE WITH CAUTION & NO WARRANTY REFERENCE & RELATED READING - https://github.com/ethereum/solidity/issues/4116 - https://medium.com/@chris_77367/explaining-unexpected-reverts-starting-with-solidity-0-4-22-3ada6e82308c - https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca - https://gist.github.com/BrendanChou/88a2eeb80947ff00bcf58ffdafeaeb61 */ library SafeERC20 { using Address for address; bytes4 constant private TRANSFER_SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)"))); bytes4 constant private TRANSFERFROM_SELECTOR = bytes4(keccak256(bytes("transferFrom(address,address,uint256)"))); bytes4 constant private APPROVE_SELECTOR = bytes4(keccak256(bytes("approve(address,uint256)"))); function safeTransfer(address _erc20Addr, address _to, uint256 _value) internal { // Must be a contract addr first! require(_erc20Addr.isContract()); (bool success, bytes memory returnValue) = // solhint-disable-next-line avoid-low-level-calls _erc20Addr.call(abi.encodeWithSelector(TRANSFER_SELECTOR, _to, _value)); // call return false when something wrong require(success); //check return value require(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0))); } function safeTransferFrom(address _erc20Addr, address _from, address _to, uint256 _value) internal { // Must be a contract addr first! require(_erc20Addr.isContract()); (bool success, bytes memory returnValue) = // solhint-disable-next-line avoid-low-level-calls _erc20Addr.call(abi.encodeWithSelector(TRANSFERFROM_SELECTOR, _from, _to, _value)); // call return false when something wrong require(success); //check return value require(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0))); } function safeApprove(address _erc20Addr, address _spender, uint256 _value) internal { // Must be a contract addr first! require(_erc20Addr.isContract()); // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. require((_value == 0) || (IERC20(_erc20Addr).allowance(address(this), _spender) == 0)); (bool success, bytes memory returnValue) = // solhint-disable-next-line avoid-low-level-calls _erc20Addr.call(abi.encodeWithSelector(APPROVE_SELECTOR, _spender, _value)); // call return false when something wrong require(success); //check return value require(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0))); } } /** * @title An Avatar holds tokens, reputation and ether for a controller */ contract Avatar is Ownable { using SafeERC20 for address; string public orgName; DAOToken public nativeToken; Reputation public nativeReputation; event GenericCall(address indexed _contract, bytes _data, uint _value, bool _success); event SendEther(uint256 _amountInWei, address indexed _to); event ExternalTokenTransfer(address indexed _externalToken, address indexed _to, uint256 _value); event ExternalTokenTransferFrom(address indexed _externalToken, address _from, address _to, uint256 _value); event ExternalTokenApproval(address indexed _externalToken, address _spender, uint256 _value); event ReceiveEther(address indexed _sender, uint256 _value); event MetaData(string _metaData); /** * @dev the constructor takes organization name, native token and reputation system and creates an avatar for a controller */ constructor(string memory _orgName, DAOToken _nativeToken, Reputation _nativeReputation) public { orgName = _orgName; nativeToken = _nativeToken; nativeReputation = _nativeReputation; } /** * @dev enables an avatar to receive ethers */ function() external payable { emit ReceiveEther(msg.sender, msg.value); } /** * @dev perform a generic call to an arbitrary contract * @param _contract the contract's address to call * @param _data ABI-encoded contract call to call `_contract` address. * @param _value value (ETH) to transfer with the transaction * @return bool success or fail * bytes - the return bytes of the called contract's function. */ function genericCall(address _contract, bytes memory _data, uint256 _value) public onlyOwner returns(bool success, bytes memory returnValue) { // solhint-disable-next-line avoid-call-value (success, returnValue) = _contract.call.value(_value)(_data); emit GenericCall(_contract, _data, _value, success); } /** * @dev send ethers from the avatar's wallet * @param _amountInWei amount to send in Wei units * @param _to send the ethers to this address * @return bool which represents success */ function sendEther(uint256 _amountInWei, address payable _to) public onlyOwner returns(bool) { _to.transfer(_amountInWei); emit SendEther(_amountInWei, _to); return true; } /** * @dev external token transfer * @param _externalToken the token contract * @param _to the destination address * @param _value the amount of tokens to transfer * @return bool which represents success */ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value) public onlyOwner returns(bool) { address(_externalToken).safeTransfer(_to, _value); emit ExternalTokenTransfer(address(_externalToken), _to, _value); return true; } /** * @dev external token transfer from a specific account * @param _externalToken the token contract * @param _from the account to spend token from * @param _to the destination address * @param _value the amount of tokens to transfer * @return bool which represents success */ function externalTokenTransferFrom( IERC20 _externalToken, address _from, address _to, uint256 _value ) public onlyOwner returns(bool) { address(_externalToken).safeTransferFrom(_from, _to, _value); emit ExternalTokenTransferFrom(address(_externalToken), _from, _to, _value); return true; } /** * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens * on behalf of msg.sender. * @param _externalToken the address of the Token Contract * @param _spender address * @param _value the amount of ether (in Wei) which the approval is referring to. * @return bool which represents a success */ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value) public onlyOwner returns(bool) { address(_externalToken).safeApprove(_spender, _value); emit ExternalTokenApproval(address(_externalToken), _spender, _value); return true; } /** * @dev metaData emits an event with a string, should contain the hash of some meta data. * @param _metaData a string representing a hash of the meta data * @return bool which represents a success */ function metaData(string memory _metaData) public onlyOwner returns(bool) { emit MetaData(_metaData); return true; } } contract GlobalConstraintInterface { enum CallPhase { Pre, Post, PreAndPost } function pre( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool); function post( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool); /** * @dev when return if this globalConstraints is pre, post or both. * @return CallPhase enum indication Pre, Post or PreAndPost. */ function when() public returns(CallPhase); } /** * @title Controller contract * @dev A controller controls the organizations tokens ,reputation and avatar. * It is subject to a set of schemes and constraints that determine its behavior. * Each scheme has it own parameters and operation permissions. */ interface ControllerInterface { /** * @dev Mint `_amount` of reputation that are assigned to `_to` . * @param _amount amount of reputation to mint * @param _to beneficiary address * @return bool which represents a success */ function mintReputation(uint256 _amount, address _to, address _avatar) external returns(bool); /** * @dev Burns `_amount` of reputation from `_from` * @param _amount amount of reputation to burn * @param _from The address that will lose the reputation * @return bool which represents a success */ function burnReputation(uint256 _amount, address _from, address _avatar) external returns(bool); /** * @dev mint tokens . * @param _amount amount of token to mint * @param _beneficiary beneficiary address * @param _avatar address * @return bool which represents a success */ function mintTokens(uint256 _amount, address _beneficiary, address _avatar) external returns(bool); /** * @dev register or update a scheme * @param _scheme the address of the scheme * @param _paramsHash a hashed configuration of the usage of the scheme * @param _permissions the permissions the new scheme will have * @param _avatar address * @return bool which represents a success */ function registerScheme(address _scheme, bytes32 _paramsHash, bytes4 _permissions, address _avatar) external returns(bool); /** * @dev unregister a scheme * @param _avatar address * @param _scheme the address of the scheme * @return bool which represents a success */ function unregisterScheme(address _scheme, address _avatar) external returns(bool); /** * @dev unregister the caller's scheme * @param _avatar address * @return bool which represents a success */ function unregisterSelf(address _avatar) external returns(bool); /** * @dev add or update Global Constraint * @param _globalConstraint the address of the global constraint to be added. * @param _params the constraint parameters hash. * @param _avatar the avatar of the organization * @return bool which represents a success */ function addGlobalConstraint(address _globalConstraint, bytes32 _params, address _avatar) external returns(bool); /** * @dev remove Global Constraint * @param _globalConstraint the address of the global constraint to be remove. * @param _avatar the organization avatar. * @return bool which represents a success */ function removeGlobalConstraint (address _globalConstraint, address _avatar) external returns(bool); /** * @dev upgrade the Controller * The function will trigger an event 'UpgradeController'. * @param _newController the address of the new controller. * @param _avatar address * @return bool which represents a success */ function upgradeController(address _newController, Avatar _avatar) external returns(bool); /** * @dev perform a generic call to an arbitrary contract * @param _contract the contract's address to call * @param _data ABI-encoded contract call to call `_contract` address. * @param _avatar the controller's avatar address * @param _value value (ETH) to transfer with the transaction * @return bool -success * bytes - the return value of the called _contract's function. */ function genericCall(address _contract, bytes calldata _data, Avatar _avatar, uint256 _value) external returns(bool, bytes memory); /** * @dev send some ether * @param _amountInWei the amount of ether (in Wei) to send * @param _to address of the beneficiary * @param _avatar address * @return bool which represents a success */ function sendEther(uint256 _amountInWei, address payable _to, Avatar _avatar) external returns(bool); /** * @dev send some amount of arbitrary ERC20 Tokens * @param _externalToken the address of the Token Contract * @param _to address of the beneficiary * @param _value the amount of ether (in Wei) to send * @param _avatar address * @return bool which represents a success */ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value, Avatar _avatar) external returns(bool); /** * @dev transfer token "from" address "to" address * One must to approve the amount of tokens which can be spend from the * "from" account.This can be done using externalTokenApprove. * @param _externalToken the address of the Token Contract * @param _from address of the account to send from * @param _to address of the beneficiary * @param _value the amount of ether (in Wei) to send * @param _avatar address * @return bool which represents a success */ function externalTokenTransferFrom( IERC20 _externalToken, address _from, address _to, uint256 _value, Avatar _avatar) external returns(bool); /** * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens * on behalf of msg.sender. * @param _externalToken the address of the Token Contract * @param _spender address * @param _value the amount of ether (in Wei) which the approval is referring to. * @return bool which represents a success */ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value, Avatar _avatar) external returns(bool); /** * @dev metaData emits an event with a string, should contain the hash of some meta data. * @param _metaData a string representing a hash of the meta data * @param _avatar Avatar * @return bool which represents a success */ function metaData(string calldata _metaData, Avatar _avatar) external returns(bool); /** * @dev getNativeReputation * @param _avatar the organization avatar. * @return organization native reputation */ function getNativeReputation(address _avatar) external view returns(address); function isSchemeRegistered( address _scheme, address _avatar) external view returns(bool); function getSchemeParameters(address _scheme, address _avatar) external view returns(bytes32); function getGlobalConstraintParameters(address _globalConstraint, address _avatar) external view returns(bytes32); function getSchemePermissions(address _scheme, address _avatar) external view returns(bytes4); /** * @dev globalConstraintsCount return the global constraint pre and post count * @return uint256 globalConstraintsPre count. * @return uint256 globalConstraintsPost count. */ function globalConstraintsCount(address _avatar) external view returns(uint, uint); function isGlobalConstraintRegistered(address _globalConstraint, address _avatar) external view returns(bool); } /* @dev abstract contract for ensuring that schemes have been registered properly * Allows setting zero Avatar in situations where the Avatar hasn't been created yet */ contract SchemeGuard is Ownable { Avatar avatar; ControllerInterface internal controller = ControllerInterface(0); /** @dev Constructor. only sets controller if given avatar is not null. * @param _avatar The avatar of the DAO. */ constructor(Avatar _avatar) public { avatar = _avatar; if (avatar != Avatar(0)) { controller = ControllerInterface(avatar.owner()); } } /** @dev modifier to check if caller is avatar */ modifier onlyAvatar() { require(address(avatar) == msg.sender, "only Avatar can call this method"); _; } /** @dev modifier to check if scheme is registered */ modifier onlyRegistered() { require(isRegistered(), "Scheme is not registered"); _; } /** @dev modifier to check if scheme is not registered */ modifier onlyNotRegistered() { require(!isRegistered(), "Scheme is registered"); _; } /** @dev modifier to check if call is a scheme that is registered */ modifier onlyRegisteredCaller() { require(isRegistered(msg.sender), "Calling scheme is not registered"); _; } /** @dev Function to set a new avatar and controller for scheme * can only be done by owner of scheme */ function setAvatar(Avatar _avatar) public onlyOwner { avatar = _avatar; controller = ControllerInterface(avatar.owner()); } /** @dev function to see if an avatar has been set and if this scheme is registered * @return true if scheme is registered */ function isRegistered() public view returns (bool) { return isRegistered(address(this)); } /** @dev function to see if an avatar has been set and if this scheme is registered * @return true if scheme is registered */ function isRegistered(address scheme) public view returns (bool) { require(avatar != Avatar(0), "Avatar is not set"); if (!(controller.isSchemeRegistered(scheme, address(avatar)))) { return false; } return true; } } /** * @title Contract managing the identity admin role */ contract IdentityAdminRole is Ownable { using Roles for Roles.Role; event IdentityAdminAdded(address indexed account); event IdentityAdminRemoved(address indexed account); Roles.Role private IdentityAdmins; /* @dev constructor. Adds caller as an admin */ constructor() internal { _addIdentityAdmin(msg.sender); } /* @dev Modifier to check if caller is an admin */ modifier onlyIdentityAdmin() { require(isIdentityAdmin(msg.sender), "not IdentityAdmin"); _; } /** * @dev Checks if account is identity admin * @param account Account to check * @return Boolean indicating if account is identity admin */ function isIdentityAdmin(address account) public view returns (bool) { return IdentityAdmins.has(account); } /** * @dev Adds a identity admin account. Is only callable by owner. * @param account Address to be added * @return true if successful */ function addIdentityAdmin(address account) public onlyOwner returns (bool) { _addIdentityAdmin(account); return true; } /** * @dev Removes a identity admin account. Is only callable by owner. * @param account Address to be removed * @return true if successful */ function removeIdentityAdmin(address account) public onlyOwner returns (bool) { _removeIdentityAdmin(account); return true; } /** * @dev Allows an admin to renounce their role */ function renounceIdentityAdmin() public { _removeIdentityAdmin(msg.sender); } /** * @dev Internal implementation of addIdentityAdmin */ function _addIdentityAdmin(address account) internal { IdentityAdmins.add(account); emit IdentityAdminAdded(account); } /** * @dev Internal implementation of removeIdentityAdmin */ function _removeIdentityAdmin(address account) internal { IdentityAdmins.remove(account); emit IdentityAdminRemoved(account); } } /* @title Identity contract responsible for whitelisting * and keeping track of amount of whitelisted users */ contract Identity is IdentityAdminRole, SchemeGuard, Pausable { using Roles for Roles.Role; using SafeMath for uint256; Roles.Role private blacklist; Roles.Role private whitelist; Roles.Role private contracts; uint256 public whitelistedCount = 0; uint256 public whitelistedContracts = 0; uint256 public authenticationPeriod = 14; mapping(address => uint256) public dateAuthenticated; mapping(address => uint256) public dateAdded; mapping(address => string) public addrToDID; mapping(bytes32 => address) public didHashToAddress; event BlacklistAdded(address indexed account); event BlacklistRemoved(address indexed account); event WhitelistedAdded(address indexed account); event WhitelistedRemoved(address indexed account); event ContractAdded(address indexed account); event ContractRemoved(address indexed account); constructor() public SchemeGuard(Avatar(0)) {} /* @dev Sets a new value for authenticationPeriod. * Can only be called by Identity Administrators. * @param period new value for authenticationPeriod */ function setAuthenticationPeriod(uint256 period) public onlyOwner whenNotPaused { authenticationPeriod = period; } /* @dev Sets the authentication date of `account` * to the current time. * Can only be called by Identity Administrators. * @param account address to change its auth date */ function authenticate(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { dateAuthenticated[account] = now; } /* @dev Adds an address as whitelisted. * Can only be called by Identity Administrators. * @param account address to add as whitelisted */ function addWhitelisted(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { _addWhitelisted(account); } /* @dev Adds an address as whitelisted under a specific ID * @param account The address to add * @param did the ID to add account under */ function addWhitelistedWithDID(address account, string memory did) public onlyRegistered onlyIdentityAdmin whenNotPaused { _addWhitelistedWithDID(account, did); } /* @dev Removes an address as whitelisted. * Can only be called by Identity Administrators. * @param account address to remove as whitelisted */ function removeWhitelisted(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { _removeWhitelisted(account); } /* @dev Renounces message sender from whitelisted */ function renounceWhitelisted() public whenNotPaused { _removeWhitelisted(msg.sender); } /* @dev Returns true if given address has been added to whitelist * @param account the address to check * @return a bool indicating weather the address is present in whitelist */ function isWhitelisted(address account) public view returns (bool) { uint256 daysSinceAuthentication = (now.sub(dateAuthenticated[account])) / 1 days; return (daysSinceAuthentication <= authenticationPeriod) && whitelist.has(account); } /* @dev Function that gives the date the given user was added * @param account The address to check * @return The date the address was added */ function lastAuthenticated(address account) public view returns (uint256) { return dateAuthenticated[account]; } // /** // * // * @dev Function to transfer whitelisted privilege to another address // * relocates did of sender to give address // * @param account The address to transfer to // */ // function transferAccount(address account) public whenNotPaused { // ERC20 token = avatar.nativeToken(); // require(!isBlacklisted(account), "Cannot transfer to blacklisted"); // require(token.balanceOf(account) == 0, "Account is already in use"); // require(isWhitelisted(msg.sender), "Requester need to be whitelisted"); // require( // keccak256(bytes(addrToDID[account])) == keccak256(bytes("")), // "address already has DID" // ); // string memory did = addrToDID[msg.sender]; // bytes32 pHash = keccak256(bytes(did)); // uint256 balance = token.balanceOf(msg.sender); // token.transferFrom(msg.sender, account, balance); // _removeWhitelisted(msg.sender); // _addWhitelisted(account); // addrToDID[account] = did; // didHashToAddress[pHash] = account; // } /* @dev Adds an address to blacklist. * Can only be called by Identity Administrators. * @param account address to add as blacklisted */ function addBlacklisted(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { blacklist.add(account); emit BlacklistAdded(account); } /* @dev Removes an address from blacklist * Can only be called by Identity Administrators. * @param account address to remove as blacklisted */ function removeBlacklisted(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { blacklist.remove(account); emit BlacklistRemoved(account); } /* @dev Function to add a Contract to list of contracts * @param account The address to add */ function addContract(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { require(isContract(account), "Given address is not a contract"); contracts.add(account); _addWhitelisted(account); emit ContractAdded(account); } /* @dev Function to remove a Contract from list of contracts * @param account The address to add */ function removeContract(address account) public onlyRegistered onlyIdentityAdmin whenNotPaused { contracts.remove(account); _removeWhitelisted(account); emit ContractRemoved(account); } /* @dev Function to check if given contract is on list of contracts. * @param address to check * @return a bool indicating if address is on list of contracts */ function isDAOContract(address account) public view returns (bool) { return contracts.has(account); } /* @dev Internal function to add to whitelisted * @param account the address to add */ function _addWhitelisted(address account) internal { whitelist.add(account); whitelistedCount += 1; dateAdded[account] = now; dateAuthenticated[account] = now; if (isContract(account)) { whitelistedContracts += 1; } emit WhitelistedAdded(account); } /* @dev Internal whitelisting with did function. * @param account the address to add * @param did the id to register account under */ function _addWhitelistedWithDID(address account, string memory did) internal { bytes32 pHash = keccak256(bytes(did)); require(didHashToAddress[pHash] == address(0), "DID already registered"); addrToDID[account] = did; didHashToAddress[pHash] = account; _addWhitelisted(account); } /* @dev Internal function to remove from whitelisted * @param account the address to add */ function _removeWhitelisted(address account) internal { whitelist.remove(account); whitelistedCount -= 1; delete dateAuthenticated[account]; if (isContract(account)) { whitelistedContracts -= 1; } string memory did = addrToDID[account]; bytes32 pHash = keccak256(bytes(did)); delete dateAuthenticated[account]; delete addrToDID[account]; delete didHashToAddress[pHash]; emit WhitelistedRemoved(account); } /* @dev Returns true if given address has been added to the blacklist * @param account the address to check * @return a bool indicating weather the address is present in the blacklist */ function isBlacklisted(address account) public view returns (bool) { return blacklist.has(account); } /* @dev Function to see if given address is a contract * @return true if address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 length; assembly { length := extcodesize(_addr) } return length > 0; } } /* @title The IdentityGuard contract * @dev Contract containing an identity and * modifiers to ensure proper access */ contract IdentityGuard is Ownable { Identity public identity; /* @dev Constructor. Checks if identity is a zero address * @param _identity The identity contract. */ constructor(Identity _identity) public { require(_identity != Identity(0), "Supplied identity is null"); identity = _identity; } /* @dev Modifier that requires the sender to be not blacklisted */ modifier onlyNotBlacklisted() { require(!identity.isBlacklisted(msg.sender), "Caller is blacklisted"); _; } /* @dev Modifier that requires the given address to be not blacklisted * @param _account The address to be checked */ modifier requireNotBlacklisted(address _account) { require(!identity.isBlacklisted(_account), "Receiver is blacklisted"); _; } /* @dev Modifier that requires the sender to be whitelisted */ modifier onlyWhitelisted() { require(identity.isWhitelisted(msg.sender), "is not whitelisted"); _; } /* @dev Modifier that requires the given address to be whitelisted * @param _account the given address */ modifier requireWhitelisted(address _account) { require(identity.isWhitelisted(_account), "is not whitelisted"); _; } /* @dev Modifier that requires the sender to be an approved DAO contract */ modifier onlyDAOContract() { require(identity.isDAOContract(msg.sender), "is not whitelisted contract"); _; } /* @dev Modifier that requires the given address to be whitelisted * @param _account the given address */ modifier requireDAOContract(address _contract) { require(identity.isDAOContract(_contract), "is not whitelisted contract"); _; } /* @dev Modifier that requires the sender to have been whitelisted * before or on the given date * @param date The time sender must have been added before */ modifier onlyAddedBefore(uint256 date) { require( identity.lastAuthenticated(msg.sender) <= date, "Was not added within period" ); _; } /* @dev Modifier that requires sender to be an identity admin */ modifier onlyIdentityAdmin() { require(identity.isIdentityAdmin(msg.sender), "not IdentityAdmin"); _; } /* @dev Allows owner to set a new identity contract if * the given identity contract has been registered as a scheme */ function setIdentity(Identity _identity) public onlyOwner { require(_identity.isRegistered(), "Identity is not registered"); identity = _identity; } } /** * @dev Contract for letting scheme add itself to identity * to allow transferring GoodDollar without paying fees * and transfer ownership to Avatar */ contract FeelessScheme is SchemeGuard, IdentityGuard { /* @dev Constructor * @param _identity The identity contract * @param _avatar The avatar of the DAO */ constructor(Identity _identity, Avatar _avatar) public SchemeGuard(_avatar) IdentityGuard(_identity) {} /* @dev Internal function to add contract to identity. * Can only be called if scheme is registered. */ function addRights() internal onlyRegistered { controller.genericCall( address(identity), abi.encodeWithSignature("addContract(address)", address(this)), avatar, 0 ); transferOwnership(address(avatar)); } /* @dev Internal function to remove contract from identity. * Can only be called if scheme is registered. */ function removeRights() internal onlyRegistered { controller.genericCall( address(identity), abi.encodeWithSignature("removeContract(address)", address(this)), avatar, 0 ); } } /// math.sol -- mixin for inline numerical wizardry // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. contract DSMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x >= y ? x : y; } function imin(int256 x, int256 y) internal pure returns (int256 z) { return x <= y ? x : y; } function imax(int256 x, int256 y) internal pure returns (int256 z) { return x >= y ? x : y; } uint256 constant WAD = 10**18; uint256 constant RAY = 10**27; function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } interface cERC20 { function mint(uint256 mintAmount) external returns (uint256); function redeemUnderlying(uint256 mintAmount) external returns (uint256); function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function balanceOf(address addr) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); } /** * @title Staking contract that donates earned interest to the DAO * allowing stakers to deposit DAI or withdraw their stake in DAI. * The contract buys cDAI and can transfer the daily interest to the DAO */ contract SimpleDAIStaking is DSMath, Pausable, FeelessScheme { using SafeMath for uint256; // Entity that holds a staker info struct Staker { // The staked DAI amount uint256 stakedDAI; // The latest block number which the // staker has staked tokens uint256 lastStake; } // The map which holds the stakers entities mapping(address => Staker) public stakers; // Emits when new DAI tokens have been staked event DAIStaked( // The staker address address indexed staker, // How many tokens have been staked uint256 daiValue ); // Emits when DAI tokens are being withdrawn event DAIStakeWithdraw( // The staker that initiate the action address indexed staker, // The initial DAI value that was staked uint256 daiValue, // The current DAI value that was staked uint256 daiActual ); // Emits when the interest is collected event InterestCollected( // Who is receives the interest address recipient, // How many cDAI tokens have been transferred uint256 cdaiValue, // The worth of the transferred tokens in DAI uint256 daiValue, // Lost amount. A result of different precisions uint256 daiPrecisionLoss ); // DAI token address ERC20 public dai; // cDAI token address cERC20 public cDai; // The block interval defines the number of // blocks that shall be passed before the // next execution of `collectUBIInterest` uint256 public blockInterval; // The last block number which // `collectUBIInterest` has been executed in uint256 public lastUBICollection; // The total staked DAI amount in the contract uint256 public totalStaked = 0; // How much of the generated interest is donated, // meaning no GD is expected in compensation, 1 in mil precision. // 100% for phase0 POC uint32 public avgInterestDonatedRatio = 1e6; // The address of the fund manager contract address public fundManager; modifier onlyFundManager { require(msg.sender == fundManager, "Only FundManager can call this method"); _; } /** * @dev Constructor * @param _dai The address of DAI * @param _cDai The address of cDAI * @param _fundManager The address of the fund manager contract * @param _blockInterval How many blocks should be passed before the next execution of `collectUBIInterest` * @param _avatar The avatar of the DAO * @param _identity The identity contract */ constructor( address _dai, address _cDai, address _fundManager, uint256 _blockInterval, Avatar _avatar, Identity _identity ) public FeelessScheme(_identity, _avatar) { dai = ERC20(_dai); cDai = cERC20(_cDai); blockInterval = _blockInterval; lastUBICollection = block.number.div(blockInterval); fundManager = _fundManager; // Adds the avatar as a pauser of this contract addPauser(address(avatar)); } /** * @dev Allows the DAO to change the fund manager contract address * @param _fundManager Address of the new contract */ function setFundManager(address _fundManager) public onlyAvatar { fundManager = _fundManager; } /** * @dev Allows a staker to deposit DAI tokens. Notice that `approve` is * needed to be executed before the execution of this method. * Can be executed only when the contract is not paused. * @param _amount The amount of DAI to stake */ function stakeDAI(uint256 _amount) public whenNotPaused { require(_amount > 0, "You need to stake a positive token amount"); require( dai.transferFrom(msg.sender, address(this), _amount) == true, "transferFrom failed, make sure you approved DAI transfer" ); // approve the transfer to cDAI dai.approve(address(cDai), _amount); // mint ctokens uint256 res = cDai.mint(_amount); // cDAI returns >0 if error happened while minting. // Makes sure that there are no errors. If an error // has occurred, DAI funds shall be returned. if (res > 0) { require(res == 0, "Minting cDai failed, funds returned"); } // updated the staker entity Staker storage staker = stakers[msg.sender]; staker.stakedDAI = staker.stakedDAI.add(_amount); staker.lastStake = block.number; // adds the staked amount to the total staked totalStaked = totalStaked.add(_amount); emit DAIStaked(msg.sender, _amount); } /** * @dev Withdraws the sender staked DAI. */ function withdrawStake() public { Staker storage staker = stakers[msg.sender]; require(staker.stakedDAI > 0, "No DAI staked"); require(cDai.redeemUnderlying(staker.stakedDAI) == 0, "Failed to redeem cDai"); uint256 daiWithdraw = staker.stakedDAI; // updates balance before transfer to prevent re-entry staker.stakedDAI = 0; totalStaked = totalStaked.sub(daiWithdraw); //redeeming in compound may result in a tiny fraction of precission error //so if we redeem 100 DAI we might get something like 99.9999999999 uint256 daiActual = dai.balanceOf(address(this)); if (daiActual < daiWithdraw) { daiWithdraw = daiActual; } require(dai.transfer(msg.sender, daiWithdraw), "withdraw transfer failed"); emit DAIStakeWithdraw(msg.sender, daiWithdraw, daiActual); } /** * @dev Calculates the worth of the staked cDAI tokens in DAI. * @return (uint256) The worth in DAI */ function currentDAIWorth() public view returns (uint256) { uint256 er = cDai.exchangeRateStored(); //TODO: why 1e10? cDai is e8 so we should convert it to e28 like exchange rate uint256 daiBalance = rmul(cDai.balanceOf(address(this)).mul(1e10), er).div(10); return daiBalance; } /** * @dev Calculates the current interest that was gained. * @return (uint256, uint256, uint256) The interest in cDAI, the interest in DAI, * the amount which is not covered by precision of DAI */ function currentUBIInterest() public view returns ( uint256, uint256, uint256 ) { uint256 er = cDai.exchangeRateStored(); uint256 daiWorth = currentDAIWorth(); if (daiWorth <= totalStaked) { return (0, 0, 0); } uint256 daiGains = daiWorth.sub(totalStaked); // mul by 1e10 to equalize precision otherwise since exchangerate // is very big, dividing by it would result in 0. uint256 cdaiGains = rdiv(daiGains.mul(1e10), er); // gets right most bits not covered by precision of cdai which is // only 8 decimals while RAY is 27 uint256 precisionLossCDaiRay = cdaiGains.mod(1e19); // lower back to 8 decimals cdaiGains = cdaiGains.div(1e19); //div by 1e10 to get results in dai precision 1e18 uint256 precisionLossDai = rmul(precisionLossCDaiRay, er).div(1e10); return (cdaiGains, daiGains, precisionLossDai); } /** * @dev Collects gained interest by fundmanager. Can be collected only once * in an interval which is defined above. * @param _recipient The recipient of cDAI gains * @return (uint256, uint256, uint256, uint32) The interest in cDAI, the interest in DAI, * the amount which is not covered by precision of DAI, how much of the generated interest is donated */ function collectUBIInterest(address _recipient) public onlyFundManager returns ( uint256, uint256, uint256, uint32 ) { // otherwise fund manager has to wait for the next interval require(_recipient != address(this), "Recipient cannot be the staking contract"); require(canCollect(), "Need to wait for the next interval"); ( uint256 cdaiGains, uint256 daiGains, uint256 precisionLossDai ) = currentUBIInterest(); lastUBICollection = block.number.div(blockInterval); if (cdaiGains > 0) require(cDai.transfer(_recipient, cdaiGains), "collect transfer failed"); emit InterestCollected(_recipient, cdaiGains, daiGains, precisionLossDai); return (cdaiGains, daiGains, precisionLossDai, avgInterestDonatedRatio); } /** * @dev Checks if enough blocks have passed so it would be possible to * execute `collectUBIInterest` according to the length of `blockInterval` * @return (bool) True if enough blocks have passed */ function canCollect() public view returns (bool) { return block.number.div(blockInterval) > lastUBICollection; } /** * @dev Start function. Adds this contract to identity as a feeless scheme. * Can only be called if scheme is registered */ function start() public onlyRegistered { addRights(); } /** * @dev making the contract inactive * NOTICE: this could theoretically result in future interest earned in cdai to remain locked * but we dont expect any other stakers but us in SimpleDAIStaking */ function end() public onlyAvatar { pause(); removeRights(); } /** * @dev method to recover any stuck erc20 tokens (ie compound COMP) * @param _token the ERC20 token to recover */ function recover(ERC20 _token) public onlyAvatar { uint256 toWithdraw = _token.balanceOf(address(this)); // recover left cDai(stakers token) only when all stakes have been withdrawn if (address(_token) == address(cDai)) { require( totalStaked == 0 && paused(), "can recover cDai only when stakes have been withdrawn" ); } require(_token.transfer(address(avatar), toWithdraw), "recover transfer failed"); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_dai","type":"address"},{"internalType":"address","name":"_cDai","type":"address"},{"internalType":"address","name":"_fundManager","type":"address"},{"internalType":"uint256","name":"_blockInterval","type":"uint256"},{"internalType":"contract Avatar","name":"_avatar","type":"address"},{"internalType":"contract Identity","name":"_identity","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"daiValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"daiActual","type":"uint256"}],"name":"DAIStakeWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"daiValue","type":"uint256"}],"name":"DAIStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"cdaiValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"daiValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"daiPrecisionLoss","type":"uint256"}],"name":"InterestCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"avgInterestDonatedRatio","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"blockInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cDai","outputs":[{"internalType":"contract cERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canCollect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"collectUBIInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentDAIWorth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentUBIInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dai","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"end","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"fundManager","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"identity","outputs":[{"internalType":"contract Identity","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"scheme","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastUBICollection","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ERC20","name":"_token","type":"address"}],"name":"recover","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Avatar","name":"_avatar","type":"address"}],"name":"setAvatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_fundManager","type":"address"}],"name":"setFundManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract Identity","name":"_identity","type":"address"}],"name":"setIdentity","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeDAI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakers","outputs":[{"internalType":"uint256","name":"stakedDAI","type":"uint256"},{"internalType":"uint256","name":"lastStake","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052600380546001600160a01b03191690556000600a55600b805463ffffffff1916620f42401790553480156200003857600080fd5b50604051620025a3380380620025a3833981810160405260c08110156200005e57600080fd5b508051602082015160408301516060840151608085015160a0909501519394929391929091808281816200009b336001600160e01b03620002bf16565b600180546001600160a81b03191661010033810291909117918290556040516001600160a01b039190920416906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3600280546001600160a01b0319166001600160a01b0383811691909117918290551615620001b557600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200016757600080fd5b505afa1580156200017c573d6000803e3d6000fd5b505050506040513d60208110156200019357600080fd5b5051600380546001600160a01b0319166001600160a01b039092169190911790555b506001600160a01b03811662000212576040805162461bcd60e51b815260206004820152601960248201527f537570706c696564206964656e74697479206973206e756c6c00000000000000604482015290519081900360640190fd5b600480546001600160a01b03199081166001600160a01b03938416179091556006805482168b841617905560078054909116918916919091179055505060088390556200026c438462000311602090811b6200187217901c565b600955600b80546001600160a01b0380871664010000000002600160201b600160c01b031990921691909117909155600254620002b391166001600160e01b036200033516565b5050505050506200041c565b620002da8160006200036a60201b62001fce1790919060201c565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b60008082116200032057600080fd5b60008284816200032c57fe5b04949350505050565b62000349336001600160e01b03620003c316565b6200035357600080fd5b62000367816001600160e01b03620002bf16565b50565b6001600160a01b0381166200037e57600080fd5b6200039382826001600160e01b03620003e616565b156200039e57600080fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6000620003e0826000620003e660201b620018c41790919060201c565b92915050565b60006001600160a01b038216620003fc57600080fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b612177806200042c6000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063817b1cd21161011a578063be9a6555116100ad578063c9b0d97b1161007c578063c9b0d97b146104aa578063e8b2467d146104b2578063efbe1c1c146104d3578063f2fde38b146104db578063f4b9fa7514610501576101fb565b8063be9a65551461046c578063bed9d86114610474578063c3c5a5471461047c578063c4c22e98146104a2576101fb565b80638da5cb5b116100e95780638da5cb5b146104155780638f32d59b1461041d5780639168ae72146104255780639b089d5514610464576101fb565b8063817b1cd2146103d75780638247cc0c146103df57806382dc1ec4146103e75780638456cb591461040d576101fb565b80633f4ba83a116101925780636209ec2d116101615780636209ec2d146103a257806364aab239146103aa5780636ef8d66d146103c7578063715018a6146103cf576101fb565b80633f4ba83a1461034657806346fbf68e1461034e5780635c975abb146103745780635d5bf1781461037c576101fb565b806322366844116101ce578063223668441461028e578063232a3060146102aa5780632c159a1a146102d057806337455990146102f4576101fb565b8063086cfca8146102005780630cd865ec1461022857806317e49ca11461024e578063210a27a914610274575b600080fd5b6102266004803603602081101561021657600080fd5b50356001600160a01b0316610509565b005b6102266004803603602081101561023e57600080fd5b50356001600160a01b03166105c4565b6102566107d7565b60408051938452602084019290925282820152519081900360600190f35b61027c610925565b60408051918252519081900360200190f35b610296610a4e565b604080519115158252519081900360200190f35b610226600480360360208110156102c057600080fd5b50356001600160a01b0316610a5e565b6102d8610aeb565b604080516001600160a01b039092168252519081900360200190f35b61031a6004803603602081101561030a57600080fd5b50356001600160a01b0316610afa565b6040805194855260208501939093528383019190915263ffffffff166060830152519081900360800190f35b610226610d5d565b6102966004803603602081101561036457600080fd5b50356001600160a01b0316610dbd565b610296610dd7565b6102266004803603602081101561039257600080fd5b50356001600160a01b0316610de0565b6102d8610ec9565b610226600480360360208110156103c057600080fd5b5035610ee0565b6102266111b2565b6102266111bd565b61027c61121e565b61027c611224565b610226600480360360208110156103fd57600080fd5b50356001600160a01b031661122a565b610226611248565b6102d86112ab565b6102966112bf565b61044b6004803603602081101561043b57600080fd5b50356001600160a01b03166112d5565b6040805192835260208301919091528051918290030190f35b6102d86112ee565b6102266112fd565b610226611359565b6102966004803603602081101561049257600080fd5b50356001600160a01b0316611622565b61027c61170e565b610296611714565b6104ba611734565b6040805163ffffffff9092168252519081900360200190f35b610226611740565b610226600480360360208110156104f157600080fd5b50356001600160a01b03166117af565b6102d86117c9565b6105116112bf565b61051a57600080fd5b600280546001600160a01b0319166001600160a01b03838116919091179182905560408051638da5cb5b60e01b815290519290911691638da5cb5b91600480820192602092909190829003018186803b15801561057657600080fd5b505afa15801561058a573d6000803e3d6000fd5b505050506040513d60208110156105a057600080fd5b5051600380546001600160a01b0319166001600160a01b0390921691909117905550565b6002546001600160a01b03163314610623576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561066d57600080fd5b505afa158015610681573d6000803e3d6000fd5b505050506040513d602081101561069757600080fd5b50516007549091506001600160a01b038381169116141561070057600a541580156106c557506106c5610dd7565b6107005760405162461bcd60e51b81526004018080602001828103825260358152602001806120446035913960400191505060405180910390fd5b6002546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810184905290519184169163a9059cbb916044808201926020929091908290030181600087803b15801561075657600080fd5b505af115801561076a573d6000803e3d6000fd5b505050506040513d602081101561078057600080fd5b50516107d3576040805162461bcd60e51b815260206004820152601760248201527f7265636f766572207472616e73666572206661696c6564000000000000000000604482015290519081900360640190fd5b5050565b600080600080600760009054906101000a90046001600160a01b03166001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d602081101561085557600080fd5b505190506000610863610925565b9050600a5481116108805750600093508392508291506109209050565b6000610897600a54836117d890919063ffffffff16565b905060006108b96108b3836402540be40063ffffffff6117f216565b85611820565b905060006108d582678ac7230489e8000063ffffffff61185516565b90506108ef82678ac7230489e8000063ffffffff61187216565b915060006109126402540be4006109068489611894565b9063ffffffff61187216565b929850929650909450505050505b909192565b600080600760009054906101000a90046001600160a01b03166001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561097657600080fd5b505afa15801561098a573d6000803e3d6000fd5b505050506040513d60208110156109a057600080fd5b5051600754604080516370a0823160e01b81523060048201529051929350600092610a4792600a9261090692610a41926402540be400926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610a0957600080fd5b505afa158015610a1d573d6000803e3d6000fd5b505050506040513d6020811015610a3357600080fd5b50519063ffffffff6117f216565b85611894565b9250505090565b6000610a5930611622565b905090565b6002546001600160a01b03163314610abd576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b600b80546001600160a01b0390921664010000000002640100000000600160c01b0319909216919091179055565b6004546001600160a01b031681565b600080600080600b60049054906101000a90046001600160a01b03166001600160a01b0316336001600160a01b031614610b655760405162461bcd60e51b81526004018080602001828103825260258152602001806120796025913960400191505060405180910390fd5b6001600160a01b038516301415610bad5760405162461bcd60e51b81526004018080602001828103825260288152602001806120c16028913960400191505060405180910390fd5b610bb5611714565b610bf05760405162461bcd60e51b81526004018080602001828103825260228152602001806120e96022913960400191505060405180910390fd5b6000806000610bfd6107d7565b925092509250610c186008544361187290919063ffffffff16565b6009558215610cf4576007546040805163a9059cbb60e01b81526001600160a01b038b81166004830152602482018790529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015610c7757600080fd5b505af1158015610c8b573d6000803e3d6000fd5b505050506040513d6020811015610ca157600080fd5b5051610cf4576040805162461bcd60e51b815260206004820152601760248201527f636f6c6c656374207472616e73666572206661696c6564000000000000000000604482015290519081900360640190fd5b604080516001600160a01b038a168152602081018590528082018490526060810183905290517f0abcfa9ece819bcdcfa052a818ce11f0b9fad8b3e3ccd98f120c40be689b690f9181900360800190a1600b549298919750955063ffffffff9091169350915050565b610d6633610dbd565b610d6f57600080fd5b60015460ff16610d7e57600080fd5b6001805460ff191690556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b6000610dcf818363ffffffff6118c416565b90505b919050565b60015460ff1690565b610de86112bf565b610df157600080fd5b806001600160a01b031663223668446040518163ffffffff1660e01b815260040160206040518083038186803b158015610e2a57600080fd5b505afa158015610e3e573d6000803e3d6000fd5b505050506040513d6020811015610e5457600080fd5b5051610ea7576040805162461bcd60e51b815260206004820152601a60248201527f4964656e74697479206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b600b5464010000000090046001600160a01b031681565b60015460ff1615610ef057600080fd5b60008111610f2f5760405162461bcd60e51b815260040180806020018281038252602981526020018061201b6029913960400191505060405180910390fd5b600654604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b158015610f8957600080fd5b505af1158015610f9d573d6000803e3d6000fd5b505050506040513d6020811015610fb357600080fd5b50511515600114610ff55760405162461bcd60e51b815260040180806020018281038252603881526020018061210b6038913960400191505060405180910390fd5b6006546007546040805163095ea7b360e01b81526001600160a01b039283166004820152602481018590529051919092169163095ea7b39160448083019260209291908290030181600087803b15801561104e57600080fd5b505af1158015611062573d6000803e3d6000fd5b505050506040513d602081101561107857600080fd5b50506007546040805163140e25ad60e31b81526004810184905290516000926001600160a01b03169163a0712d6891602480830192602092919082900301818787803b1580156110c757600080fd5b505af11580156110db573d6000803e3d6000fd5b505050506040513d60208110156110f157600080fd5b5051905080156111385780156111385760405162461bcd60e51b815260040180806020018281038252602381526020018061209e6023913960400191505060405180910390fd5b3360009081526005602052604090208054611159908463ffffffff6118f916565b8155436001820155600a54611174908463ffffffff6118f916565b600a5560408051848152905133917f39f13ee9b63dd3ac2e710600c086583db75aed574725071a694419f706d17244919081900360200190a2505050565b6111bb3361190b565b565b6111c56112bf565b6111ce57600080fd5b60015460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360018054610100600160a81b0319169055565b600a5481565b60095481565b61123333610dbd565b61123c57600080fd5b61124581611953565b50565b61125133610dbd565b61125a57600080fd5b60015460ff161561126a57600080fd5b6001805460ff1916811790556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b60015461010090046001600160a01b031690565b60015461010090046001600160a01b0316331490565b6005602052600090815260409020805460019091015482565b6007546001600160a01b031681565b611305610a4e565b611351576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b6111bb61199b565b33600090815260056020526040902080546113ab576040805162461bcd60e51b815260206004820152600d60248201526c139bc8111052481cdd185ad959609a1b604482015290519081900360640190fd5b60075481546040805163852a12e360e01b81526004810192909252516001600160a01b039092169163852a12e3916024808201926020929091908290030181600087803b1580156113fb57600080fd5b505af115801561140f573d6000803e3d6000fd5b505050506040513d602081101561142557600080fd5b505115611471576040805162461bcd60e51b81526020600482015260156024820152744661696c656420746f2072656465656d206344616960581b604482015290519081900360640190fd5b805460008255600a5461148a908263ffffffff6117d816565b600a55600654604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156114d857600080fd5b505afa1580156114ec573d6000803e3d6000fd5b505050506040513d602081101561150257600080fd5b5051905081811015611512578091505b6006546040805163a9059cbb60e01b81523360048201526024810185905290516001600160a01b039092169163a9059cbb916044808201926020929091908290030181600087803b15801561156657600080fd5b505af115801561157a573d6000803e3d6000fd5b505050506040513d602081101561159057600080fd5b50516115e3576040805162461bcd60e51b815260206004820152601860248201527f7769746864726177207472616e73666572206661696c65640000000000000000604482015290519081900360640190fd5b6040805183815260208101839052815133927f7441c5625c09ad27ec4eec0984408b247a5ec0cbb33cb619115a4551f71798e7928290030190a2505050565b6002546000906001600160a01b0316611676576040805162461bcd60e51b8152602060048201526011602482015270105d985d185c881a5cc81b9bdd081cd95d607a1b604482015290519081900360640190fd5b60035460025460408051639be2faed60e01b81526001600160a01b038681166004830152928316602482015290519190921691639be2faed916044808301926020929190829003018186803b1580156116ce57600080fd5b505afa1580156116e2573d6000803e3d6000fd5b505050506040513d60208110156116f857600080fd5b505161170657506000610dd2565b506001919050565b60085481565b600060095461172e6008544361187290919063ffffffff16565b11905090565b600b5463ffffffff1681565b6002546001600160a01b0316331461179f576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b6117a7611248565b6111bb611c05565b6117b76112bf565b6117c057600080fd5b61124581611e5a565b6006546001600160a01b031681565b6000828211156117e757600080fd5b508082035b92915050565b600082611801575060006117ec565b8282028284828161180e57fe5b041461181957600080fd5b9392505050565b60008161184661183c856b033b2e3c9fd0803ce8000000611ed4565b6002855b04611f37565b8161184d57fe5b049392505050565b60008161186157600080fd5b81838161186a57fe5b069392505050565b600080821161188057600080fd5b600082848161188b57fe5b04949350505050565b60006b033b2e3c9fd0803ce80000006118466118b08585611ed4565b60026b033b2e3c9fd0803ce8000000611840565b60006001600160a01b0382166118d957600080fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b60008282018381101561181957600080fd5b61191c60008263ffffffff611f8616565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b61196460008263ffffffff611fce16565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b6119a3610a4e565b6119ef576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b600354600480546040805130602480830191909152825180830382018152604492830184526020810180516001600160e01b0316635f539d6960e01b17815260025494516368db844d60e11b81526001600160a01b039687169781018881529587169481018590526000606482018190526080948201948552835160848301528351979099169863d1b7089a9897939690949093909260a49092019190808383885b83811015611aa9578181015183820152602001611a91565b50505050905090810190601f168015611ad65780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611af857600080fd5b505af1158015611b0c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015611b3557600080fd5b815160208301805160405192949293830192919084640100000000821115611b5c57600080fd5b908301906020820185811115611b7157600080fd5b8251640100000000811182820188101715611b8b57600080fd5b82525081516020918201929091019080838360005b83811015611bb8578181015183820152602001611ba0565b50505050905090810190601f168015611be55780820380516001836020036101000a031916815260200191505b5060405250506002546111bb93506001600160a01b031691506117af9050565b611c0d610a4e565b611c59576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b600354600480546040805130602480830191909152825180830382018152604492830184526020810180516001600160e01b031663c375c2ef60e01b17815260025494516368db844d60e11b81526001600160a01b039687169781018881529587169481018590526000606482018190526080948201948552835160848301528351979099169863d1b7089a9897939690949093909260a49092019190808383885b83811015611d13578181015183820152602001611cfb565b50505050905090810190601f168015611d405780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611d6257600080fd5b505af1158015611d76573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015611d9f57600080fd5b815160208301805160405192949293830192919084640100000000821115611dc657600080fd5b908301906020820185811115611ddb57600080fd5b8251640100000000811182820188101715611df557600080fd5b82525081516020918201929091019080838360005b83811015611e22578181015183820152602001611e0a565b50505050905090810190601f168015611e4f5780820380516001836020036101000a031916815260200191505b506040525050505050565b6001600160a01b038116611e6d57600080fd5b6001546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6000811580611eef57505080820282828281611eec57fe5b04145b6117ec576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b808201828110156117ec576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b6001600160a01b038116611f9957600080fd5b611fa382826118c4565b611fac57600080fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6001600160a01b038116611fe157600080fd5b611feb82826118c4565b15611ff557600080fd5b6001600160a01b0316600090815260209190915260409020805460ff1916600117905556fe596f75206e65656420746f207374616b65206120706f73697469766520746f6b656e20616d6f756e7463616e207265636f7665722063446169206f6e6c79207768656e207374616b65732068617665206265656e2077697468647261776e4f6e6c792046756e644d616e616765722063616e2063616c6c2074686973206d6574686f644d696e74696e672063446169206661696c65642c2066756e64732072657475726e6564526563697069656e742063616e6e6f7420626520746865207374616b696e6720636f6e74726163744e65656420746f207761697420666f7220746865206e65787420696e74657276616c7472616e7366657246726f6d206661696c65642c206d616b65207375726520796f7520617070726f76656420444149207472616e73666572a265627a7a723158208c8b260f403aa9f875b4927de2b87ac43fc28a609654fac761f86260fafcf8e264736f6c634300051000320000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643000000000000000000000000bdfd60f3ae73329d33ebe17d78383defd72643ad00000000000000000000000000000000000000000000000000000000000016800000000000000000000000001ecfd1afb601c406ff0e13c3485f2d75699b681700000000000000000000000076e76e10ac308a1d54a00f9df27edce4801f288b
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063817b1cd21161011a578063be9a6555116100ad578063c9b0d97b1161007c578063c9b0d97b146104aa578063e8b2467d146104b2578063efbe1c1c146104d3578063f2fde38b146104db578063f4b9fa7514610501576101fb565b8063be9a65551461046c578063bed9d86114610474578063c3c5a5471461047c578063c4c22e98146104a2576101fb565b80638da5cb5b116100e95780638da5cb5b146104155780638f32d59b1461041d5780639168ae72146104255780639b089d5514610464576101fb565b8063817b1cd2146103d75780638247cc0c146103df57806382dc1ec4146103e75780638456cb591461040d576101fb565b80633f4ba83a116101925780636209ec2d116101615780636209ec2d146103a257806364aab239146103aa5780636ef8d66d146103c7578063715018a6146103cf576101fb565b80633f4ba83a1461034657806346fbf68e1461034e5780635c975abb146103745780635d5bf1781461037c576101fb565b806322366844116101ce578063223668441461028e578063232a3060146102aa5780632c159a1a146102d057806337455990146102f4576101fb565b8063086cfca8146102005780630cd865ec1461022857806317e49ca11461024e578063210a27a914610274575b600080fd5b6102266004803603602081101561021657600080fd5b50356001600160a01b0316610509565b005b6102266004803603602081101561023e57600080fd5b50356001600160a01b03166105c4565b6102566107d7565b60408051938452602084019290925282820152519081900360600190f35b61027c610925565b60408051918252519081900360200190f35b610296610a4e565b604080519115158252519081900360200190f35b610226600480360360208110156102c057600080fd5b50356001600160a01b0316610a5e565b6102d8610aeb565b604080516001600160a01b039092168252519081900360200190f35b61031a6004803603602081101561030a57600080fd5b50356001600160a01b0316610afa565b6040805194855260208501939093528383019190915263ffffffff166060830152519081900360800190f35b610226610d5d565b6102966004803603602081101561036457600080fd5b50356001600160a01b0316610dbd565b610296610dd7565b6102266004803603602081101561039257600080fd5b50356001600160a01b0316610de0565b6102d8610ec9565b610226600480360360208110156103c057600080fd5b5035610ee0565b6102266111b2565b6102266111bd565b61027c61121e565b61027c611224565b610226600480360360208110156103fd57600080fd5b50356001600160a01b031661122a565b610226611248565b6102d86112ab565b6102966112bf565b61044b6004803603602081101561043b57600080fd5b50356001600160a01b03166112d5565b6040805192835260208301919091528051918290030190f35b6102d86112ee565b6102266112fd565b610226611359565b6102966004803603602081101561049257600080fd5b50356001600160a01b0316611622565b61027c61170e565b610296611714565b6104ba611734565b6040805163ffffffff9092168252519081900360200190f35b610226611740565b610226600480360360208110156104f157600080fd5b50356001600160a01b03166117af565b6102d86117c9565b6105116112bf565b61051a57600080fd5b600280546001600160a01b0319166001600160a01b03838116919091179182905560408051638da5cb5b60e01b815290519290911691638da5cb5b91600480820192602092909190829003018186803b15801561057657600080fd5b505afa15801561058a573d6000803e3d6000fd5b505050506040513d60208110156105a057600080fd5b5051600380546001600160a01b0319166001600160a01b0390921691909117905550565b6002546001600160a01b03163314610623576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561066d57600080fd5b505afa158015610681573d6000803e3d6000fd5b505050506040513d602081101561069757600080fd5b50516007549091506001600160a01b038381169116141561070057600a541580156106c557506106c5610dd7565b6107005760405162461bcd60e51b81526004018080602001828103825260358152602001806120446035913960400191505060405180910390fd5b6002546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810184905290519184169163a9059cbb916044808201926020929091908290030181600087803b15801561075657600080fd5b505af115801561076a573d6000803e3d6000fd5b505050506040513d602081101561078057600080fd5b50516107d3576040805162461bcd60e51b815260206004820152601760248201527f7265636f766572207472616e73666572206661696c6564000000000000000000604482015290519081900360640190fd5b5050565b600080600080600760009054906101000a90046001600160a01b03166001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d602081101561085557600080fd5b505190506000610863610925565b9050600a5481116108805750600093508392508291506109209050565b6000610897600a54836117d890919063ffffffff16565b905060006108b96108b3836402540be40063ffffffff6117f216565b85611820565b905060006108d582678ac7230489e8000063ffffffff61185516565b90506108ef82678ac7230489e8000063ffffffff61187216565b915060006109126402540be4006109068489611894565b9063ffffffff61187216565b929850929650909450505050505b909192565b600080600760009054906101000a90046001600160a01b03166001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561097657600080fd5b505afa15801561098a573d6000803e3d6000fd5b505050506040513d60208110156109a057600080fd5b5051600754604080516370a0823160e01b81523060048201529051929350600092610a4792600a9261090692610a41926402540be400926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610a0957600080fd5b505afa158015610a1d573d6000803e3d6000fd5b505050506040513d6020811015610a3357600080fd5b50519063ffffffff6117f216565b85611894565b9250505090565b6000610a5930611622565b905090565b6002546001600160a01b03163314610abd576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b600b80546001600160a01b0390921664010000000002640100000000600160c01b0319909216919091179055565b6004546001600160a01b031681565b600080600080600b60049054906101000a90046001600160a01b03166001600160a01b0316336001600160a01b031614610b655760405162461bcd60e51b81526004018080602001828103825260258152602001806120796025913960400191505060405180910390fd5b6001600160a01b038516301415610bad5760405162461bcd60e51b81526004018080602001828103825260288152602001806120c16028913960400191505060405180910390fd5b610bb5611714565b610bf05760405162461bcd60e51b81526004018080602001828103825260228152602001806120e96022913960400191505060405180910390fd5b6000806000610bfd6107d7565b925092509250610c186008544361187290919063ffffffff16565b6009558215610cf4576007546040805163a9059cbb60e01b81526001600160a01b038b81166004830152602482018790529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015610c7757600080fd5b505af1158015610c8b573d6000803e3d6000fd5b505050506040513d6020811015610ca157600080fd5b5051610cf4576040805162461bcd60e51b815260206004820152601760248201527f636f6c6c656374207472616e73666572206661696c6564000000000000000000604482015290519081900360640190fd5b604080516001600160a01b038a168152602081018590528082018490526060810183905290517f0abcfa9ece819bcdcfa052a818ce11f0b9fad8b3e3ccd98f120c40be689b690f9181900360800190a1600b549298919750955063ffffffff9091169350915050565b610d6633610dbd565b610d6f57600080fd5b60015460ff16610d7e57600080fd5b6001805460ff191690556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b6000610dcf818363ffffffff6118c416565b90505b919050565b60015460ff1690565b610de86112bf565b610df157600080fd5b806001600160a01b031663223668446040518163ffffffff1660e01b815260040160206040518083038186803b158015610e2a57600080fd5b505afa158015610e3e573d6000803e3d6000fd5b505050506040513d6020811015610e5457600080fd5b5051610ea7576040805162461bcd60e51b815260206004820152601a60248201527f4964656e74697479206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b600b5464010000000090046001600160a01b031681565b60015460ff1615610ef057600080fd5b60008111610f2f5760405162461bcd60e51b815260040180806020018281038252602981526020018061201b6029913960400191505060405180910390fd5b600654604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b158015610f8957600080fd5b505af1158015610f9d573d6000803e3d6000fd5b505050506040513d6020811015610fb357600080fd5b50511515600114610ff55760405162461bcd60e51b815260040180806020018281038252603881526020018061210b6038913960400191505060405180910390fd5b6006546007546040805163095ea7b360e01b81526001600160a01b039283166004820152602481018590529051919092169163095ea7b39160448083019260209291908290030181600087803b15801561104e57600080fd5b505af1158015611062573d6000803e3d6000fd5b505050506040513d602081101561107857600080fd5b50506007546040805163140e25ad60e31b81526004810184905290516000926001600160a01b03169163a0712d6891602480830192602092919082900301818787803b1580156110c757600080fd5b505af11580156110db573d6000803e3d6000fd5b505050506040513d60208110156110f157600080fd5b5051905080156111385780156111385760405162461bcd60e51b815260040180806020018281038252602381526020018061209e6023913960400191505060405180910390fd5b3360009081526005602052604090208054611159908463ffffffff6118f916565b8155436001820155600a54611174908463ffffffff6118f916565b600a5560408051848152905133917f39f13ee9b63dd3ac2e710600c086583db75aed574725071a694419f706d17244919081900360200190a2505050565b6111bb3361190b565b565b6111c56112bf565b6111ce57600080fd5b60015460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360018054610100600160a81b0319169055565b600a5481565b60095481565b61123333610dbd565b61123c57600080fd5b61124581611953565b50565b61125133610dbd565b61125a57600080fd5b60015460ff161561126a57600080fd5b6001805460ff1916811790556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b60015461010090046001600160a01b031690565b60015461010090046001600160a01b0316331490565b6005602052600090815260409020805460019091015482565b6007546001600160a01b031681565b611305610a4e565b611351576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b6111bb61199b565b33600090815260056020526040902080546113ab576040805162461bcd60e51b815260206004820152600d60248201526c139bc8111052481cdd185ad959609a1b604482015290519081900360640190fd5b60075481546040805163852a12e360e01b81526004810192909252516001600160a01b039092169163852a12e3916024808201926020929091908290030181600087803b1580156113fb57600080fd5b505af115801561140f573d6000803e3d6000fd5b505050506040513d602081101561142557600080fd5b505115611471576040805162461bcd60e51b81526020600482015260156024820152744661696c656420746f2072656465656d206344616960581b604482015290519081900360640190fd5b805460008255600a5461148a908263ffffffff6117d816565b600a55600654604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156114d857600080fd5b505afa1580156114ec573d6000803e3d6000fd5b505050506040513d602081101561150257600080fd5b5051905081811015611512578091505b6006546040805163a9059cbb60e01b81523360048201526024810185905290516001600160a01b039092169163a9059cbb916044808201926020929091908290030181600087803b15801561156657600080fd5b505af115801561157a573d6000803e3d6000fd5b505050506040513d602081101561159057600080fd5b50516115e3576040805162461bcd60e51b815260206004820152601860248201527f7769746864726177207472616e73666572206661696c65640000000000000000604482015290519081900360640190fd5b6040805183815260208101839052815133927f7441c5625c09ad27ec4eec0984408b247a5ec0cbb33cb619115a4551f71798e7928290030190a2505050565b6002546000906001600160a01b0316611676576040805162461bcd60e51b8152602060048201526011602482015270105d985d185c881a5cc81b9bdd081cd95d607a1b604482015290519081900360640190fd5b60035460025460408051639be2faed60e01b81526001600160a01b038681166004830152928316602482015290519190921691639be2faed916044808301926020929190829003018186803b1580156116ce57600080fd5b505afa1580156116e2573d6000803e3d6000fd5b505050506040513d60208110156116f857600080fd5b505161170657506000610dd2565b506001919050565b60085481565b600060095461172e6008544361187290919063ffffffff16565b11905090565b600b5463ffffffff1681565b6002546001600160a01b0316331461179f576040805162461bcd60e51b815260206004820181905260248201527f6f6e6c79204176617461722063616e2063616c6c2074686973206d6574686f64604482015290519081900360640190fd5b6117a7611248565b6111bb611c05565b6117b76112bf565b6117c057600080fd5b61124581611e5a565b6006546001600160a01b031681565b6000828211156117e757600080fd5b508082035b92915050565b600082611801575060006117ec565b8282028284828161180e57fe5b041461181957600080fd5b9392505050565b60008161184661183c856b033b2e3c9fd0803ce8000000611ed4565b6002855b04611f37565b8161184d57fe5b049392505050565b60008161186157600080fd5b81838161186a57fe5b069392505050565b600080821161188057600080fd5b600082848161188b57fe5b04949350505050565b60006b033b2e3c9fd0803ce80000006118466118b08585611ed4565b60026b033b2e3c9fd0803ce8000000611840565b60006001600160a01b0382166118d957600080fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b60008282018381101561181957600080fd5b61191c60008263ffffffff611f8616565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b61196460008263ffffffff611fce16565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b6119a3610a4e565b6119ef576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b600354600480546040805130602480830191909152825180830382018152604492830184526020810180516001600160e01b0316635f539d6960e01b17815260025494516368db844d60e11b81526001600160a01b039687169781018881529587169481018590526000606482018190526080948201948552835160848301528351979099169863d1b7089a9897939690949093909260a49092019190808383885b83811015611aa9578181015183820152602001611a91565b50505050905090810190601f168015611ad65780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611af857600080fd5b505af1158015611b0c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015611b3557600080fd5b815160208301805160405192949293830192919084640100000000821115611b5c57600080fd5b908301906020820185811115611b7157600080fd5b8251640100000000811182820188101715611b8b57600080fd5b82525081516020918201929091019080838360005b83811015611bb8578181015183820152602001611ba0565b50505050905090810190601f168015611be55780820380516001836020036101000a031916815260200191505b5060405250506002546111bb93506001600160a01b031691506117af9050565b611c0d610a4e565b611c59576040805162461bcd60e51b815260206004820152601860248201527714d8da195b59481a5cc81b9bdd081c9959da5cdd195c995960421b604482015290519081900360640190fd5b600354600480546040805130602480830191909152825180830382018152604492830184526020810180516001600160e01b031663c375c2ef60e01b17815260025494516368db844d60e11b81526001600160a01b039687169781018881529587169481018590526000606482018190526080948201948552835160848301528351979099169863d1b7089a9897939690949093909260a49092019190808383885b83811015611d13578181015183820152602001611cfb565b50505050905090810190601f168015611d405780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611d6257600080fd5b505af1158015611d76573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015611d9f57600080fd5b815160208301805160405192949293830192919084640100000000821115611dc657600080fd5b908301906020820185811115611ddb57600080fd5b8251640100000000811182820188101715611df557600080fd5b82525081516020918201929091019080838360005b83811015611e22578181015183820152602001611e0a565b50505050905090810190601f168015611e4f5780820380516001836020036101000a031916815260200191505b506040525050505050565b6001600160a01b038116611e6d57600080fd5b6001546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6000811580611eef57505080820282828281611eec57fe5b04145b6117ec576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b808201828110156117ec576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b6001600160a01b038116611f9957600080fd5b611fa382826118c4565b611fac57600080fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6001600160a01b038116611fe157600080fd5b611feb82826118c4565b15611ff557600080fd5b6001600160a01b0316600090815260209190915260409020805460ff1916600117905556fe596f75206e65656420746f207374616b65206120706f73697469766520746f6b656e20616d6f756e7463616e207265636f7665722063446169206f6e6c79207768656e207374616b65732068617665206265656e2077697468647261776e4f6e6c792046756e644d616e616765722063616e2063616c6c2074686973206d6574686f644d696e74696e672063446169206661696c65642c2066756e64732072657475726e6564526563697069656e742063616e6e6f7420626520746865207374616b696e6720636f6e74726163744e65656420746f207761697420666f7220746865206e65787420696e74657276616c7472616e7366657246726f6d206661696c65642c206d616b65207375726520796f7520617070726f76656420444149207472616e73666572a265627a7a723158208c8b260f403aa9f875b4927de2b87ac43fc28a609654fac761f86260fafcf8e264736f6c63430005100032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643000000000000000000000000bdfd60f3ae73329d33ebe17d78383defd72643ad00000000000000000000000000000000000000000000000000000000000016800000000000000000000000001ecfd1afb601c406ff0e13c3485f2d75699b681700000000000000000000000076e76e10ac308a1d54a00f9df27edce4801f288b
-----Decoded View---------------
Arg [0] : _dai (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [1] : _cDai (address): 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643
Arg [2] : _fundManager (address): 0xbDFD60f3aE73329D33ebe17d78383DEfd72643Ad
Arg [3] : _blockInterval (uint256): 5760
Arg [4] : _avatar (address): 0x1ecFD1afb601C406fF0e13c3485f2d75699b6817
Arg [5] : _identity (address): 0x76e76e10Ac308A1D54a00f9df27EdCE4801F288b
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [1] : 0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643
Arg [2] : 000000000000000000000000bdfd60f3ae73329d33ebe17d78383defd72643ad
Arg [3] : 0000000000000000000000000000000000000000000000000000000000001680
Arg [4] : 0000000000000000000000001ecfd1afb601c406ff0e13c3485f2d75699b6817
Arg [5] : 00000000000000000000000076e76e10ac308a1d54a00f9df27edce4801f288b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.