Contract Overview
Transactions:
729 txns
Latest 25 transactions from a total of 729 transactions
(+3 PendingTxns)
[ Download CSV Export ]
Latest 25 Internal Transaction, Click here to view more Internal Transactions as a result of Contract Execution
[ Download CSV Export ]
Contract Source Code Verified (Exact Match)
Contract Name: | DarknodeRewardVault |
Compiler Version: | v0.4.25+commit.59dbf8f1 |
Optimization Enabled: | No |
Runs (Optimizer): | 200 |
Contract Source Code
pragma solidity ^0.4.25; /** * @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 public owner; event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(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 OwnershipRenounced(owner); 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 ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting '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; } c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; assert(c >= a); return c; } } /** * @title Basic token * @dev Basic version of StandardToken, with no allowances. */ contract BasicToken is ERC20Basic { using SafeMath for uint256; mapping(address => uint256) balances; uint256 totalSupply_; /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return totalSupply_; } /** * @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) { require(_to != address(0)); require(_value <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } /** * @dev Gets the balance of the specified address. * @param _owner The address to query the 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]; } } /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * https://github.com/ethereum/EIPs/issues/20 * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol */ contract StandardToken is ERC20, BasicToken { mapping (address => mapping (address => uint256)) internal allowed; /** * @dev Transfer tokens from one address to another * @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) { require(_to != address(0)); require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); emit Transfer(_from, _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) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * @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 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 * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseApproval( address _spender, uint256 _addedValue ) public returns (bool) { 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 * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseApproval( address _spender, uint256 _subtractedValue ) public returns (bool) { uint256 oldValue = allowed[msg.sender][_spender]; if (_subtractedValue > oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } } /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. */ contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; /** * @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() onlyOwner whenNotPaused public { paused = true; emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyOwner whenPaused public { paused = false; emit Unpause(); } } /** * @title Pausable token * @dev StandardToken modified with pausable transfers. **/ contract PausableToken is StandardToken, Pausable { function transfer( address _to, uint256 _value ) public whenNotPaused returns (bool) { return super.transfer(_to, _value); } function transferFrom( address _from, address _to, uint256 _value ) public whenNotPaused returns (bool) { return super.transferFrom(_from, _to, _value); } function approve( address _spender, uint256 _value ) public whenNotPaused returns (bool) { return super.approve(_spender, _value); } function increaseApproval( address _spender, uint _addedValue ) public whenNotPaused returns (bool success) { return super.increaseApproval(_spender, _addedValue); } function decreaseApproval( address _spender, uint _subtractedValue ) public whenNotPaused returns (bool success) { return super.decreaseApproval(_spender, _subtractedValue); } } /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ contract BurnableToken is BasicToken { event Burn(address indexed burner, uint256 value); /** * @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); } function _burn(address _who, uint256 _value) internal { require(_value <= balances[_who]); // no need to require value <= totalSupply, since that would imply the // sender's balance is greater than the totalSupply, which *should* be an assertion failure balances[_who] = balances[_who].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_who, _value); emit Transfer(_who, address(0), _value); } } contract RepublicToken is PausableToken, BurnableToken { string public constant name = "Republic Token"; string public constant symbol = "REN"; uint8 public constant decimals = 18; uint256 public constant INITIAL_SUPPLY = 1000000000 * 10**uint256(decimals); /// @notice The RepublicToken Constructor. constructor() public { totalSupply_ = INITIAL_SUPPLY; balances[msg.sender] = INITIAL_SUPPLY; } function transferTokens(address beneficiary, uint256 amount) public onlyOwner returns (bool) { /* solium-disable error-reason */ require(amount > 0); balances[owner] = balances[owner].sub(amount); balances[beneficiary] = balances[beneficiary].add(amount); emit Transfer(owner, beneficiary, amount); return true; } } /** * @notice LinkedList is a library for a circular double linked list. */ library LinkedList { /* * @notice A permanent NULL node (0x0) in the circular double linked list. * NULL.next is the head, and NULL.previous is the tail. */ address public constant NULL = 0x0; /** * @notice A node points to the node before it, and the node after it. If * node.previous = NULL, then the node is the head of the list. If * node.next = NULL, then the node is the tail of the list. */ struct Node { bool inList; address previous; address next; } /** * @notice LinkedList uses a mapping from address to nodes. Each address * uniquely identifies a node, and in this way they are used like pointers. */ struct List { mapping (address => Node) list; } /** * @notice Insert a new node before an existing node. * * @param self The list being used. * @param target The existing node in the list. * @param newNode The next node to insert before the target. */ function insertBefore(List storage self, address target, address newNode) internal { require(!isInList(self, newNode), "already in list"); require(isInList(self, target) || target == NULL, "not in list"); // It is expected that this value is sometimes NULL. address prev = self.list[target].previous; self.list[newNode].next = target; self.list[newNode].previous = prev; self.list[target].previous = newNode; self.list[prev].next = newNode; self.list[newNode].inList = true; } /** * @notice Insert a new node after an existing node. * * @param self The list being used. * @param target The existing node in the list. * @param newNode The next node to insert after the target. */ function insertAfter(List storage self, address target, address newNode) internal { require(!isInList(self, newNode), "already in list"); require(isInList(self, target) || target == NULL, "not in list"); // It is expected that this value is sometimes NULL. address n = self.list[target].next; self.list[newNode].previous = target; self.list[newNode].next = n; self.list[target].next = newNode; self.list[n].previous = newNode; self.list[newNode].inList = true; } /** * @notice Remove a node from the list, and fix the previous and next * pointers that are pointing to the removed node. Removing anode that is not * in the list will do nothing. * * @param self The list being using. * @param node The node in the list to be removed. */ function remove(List storage self, address node) internal { require(isInList(self, node), "not in list"); if (node == NULL) { return; } address p = self.list[node].previous; address n = self.list[node].next; self.list[p].next = n; self.list[n].previous = p; // Deleting the node should set this value to false, but we set it here for // explicitness. self.list[node].inList = false; delete self.list[node]; } /** * @notice Insert a node at the beginning of the list. * * @param self The list being used. * @param node The node to insert at the beginning of the list. */ function prepend(List storage self, address node) internal { // isInList(node) is checked in insertBefore insertBefore(self, begin(self), node); } /** * @notice Insert a node at the end of the list. * * @param self The list being used. * @param node The node to insert at the end of the list. */ function append(List storage self, address node) internal { // isInList(node) is checked in insertBefore insertAfter(self, end(self), node); } function swap(List storage self, address left, address right) internal { // isInList(left) and isInList(right) are checked in remove address previousRight = self.list[right].previous; remove(self, right); insertAfter(self, left, right); remove(self, left); insertAfter(self, previousRight, left); } function isInList(List storage self, address node) internal view returns (bool) { return self.list[node].inList; } /** * @notice Get the node at the beginning of a double linked list. * * @param self The list being used. * * @return A address identifying the node at the beginning of the double * linked list. */ function begin(List storage self) internal view returns (address) { return self.list[NULL].next; } /** * @notice Get the node at the end of a double linked list. * * @param self The list being used. * * @return A address identifying the node at the end of the double linked * list. */ function end(List storage self) internal view returns (address) { return self.list[NULL].previous; } function next(List storage self, address node) internal view returns (address) { require(isInList(self, node), "not in list"); return self.list[node].next; } function previous(List storage self, address node) internal view returns (address) { require(isInList(self, node), "not in list"); return self.list[node].previous; } } /// @notice This contract stores data and funds for the DarknodeRegistry /// contract. The data / fund logic and storage have been separated to improve /// upgradability. contract DarknodeRegistryStore is Ownable { string public VERSION; // Passed in as a constructor parameter. /// @notice Darknodes are stored in the darknode struct. The owner is the /// address that registered the darknode, the bond is the amount of REN that /// was transferred during registration, and the public key is the /// encryption key that should be used when sending sensitive information to /// the darknode. struct Darknode { // The owner of a Darknode is the address that called the register // function. The owner is the only address that is allowed to // deregister the Darknode, unless the Darknode is slashed for // malicious behavior. address owner; // The bond is the amount of REN submitted as a bond by the Darknode. // This amount is reduced when the Darknode is slashed for malicious // behavior. uint256 bond; // The block number at which the Darknode is considered registered. uint256 registeredAt; // The block number at which the Darknode is considered deregistered. uint256 deregisteredAt; // The public key used by this Darknode for encrypting sensitive data // off chain. It is assumed that the Darknode has access to the // respective private key, and that there is an agreement on the format // of the public key. bytes publicKey; } /// Registry data. mapping(address => Darknode) private darknodeRegistry; LinkedList.List private darknodes; // RepublicToken. RepublicToken public ren; /// @notice The contract constructor. /// /// @param _VERSION A string defining the contract version. /// @param _ren The address of the RepublicToken contract. constructor( string _VERSION, RepublicToken _ren ) public { VERSION = _VERSION; ren = _ren; } /// @notice Instantiates a darknode and appends it to the darknodes /// linked-list. /// /// @param _darknodeID The darknode's ID. /// @param _darknodeOwner The darknode's owner's address /// @param _bond The darknode's bond value /// @param _publicKey The darknode's public key /// @param _registeredAt The time stamp when the darknode is registered. /// @param _deregisteredAt The time stamp when the darknode is deregistered. function appendDarknode( address _darknodeID, address _darknodeOwner, uint256 _bond, bytes _publicKey, uint256 _registeredAt, uint256 _deregisteredAt ) external onlyOwner { Darknode memory darknode = Darknode({ owner: _darknodeOwner, bond: _bond, publicKey: _publicKey, registeredAt: _registeredAt, deregisteredAt: _deregisteredAt }); darknodeRegistry[_darknodeID] = darknode; LinkedList.append(darknodes, _darknodeID); } /// @notice Returns the address of the first darknode in the store function begin() external view onlyOwner returns(address) { return LinkedList.begin(darknodes); } /// @notice Returns the address of the next darknode in the store after the /// given address. function next(address darknodeID) external view onlyOwner returns(address) { return LinkedList.next(darknodes, darknodeID); } /// @notice Removes a darknode from the store and transfers its bond to the /// owner of this contract. function removeDarknode(address darknodeID) external onlyOwner { uint256 bond = darknodeRegistry[darknodeID].bond; delete darknodeRegistry[darknodeID]; LinkedList.remove(darknodes, darknodeID); require(ren.transfer(owner, bond), "bond transfer failed"); } /// @notice Updates the bond of the darknode. If the bond is being /// decreased, the difference is sent to the owner of this contract. function updateDarknodeBond(address darknodeID, uint256 bond) external onlyOwner { uint256 previousBond = darknodeRegistry[darknodeID].bond; darknodeRegistry[darknodeID].bond = bond; if (previousBond > bond) { require(ren.transfer(owner, previousBond - bond), "cannot transfer bond"); } } /// @notice Updates the deregistration timestamp of a darknode. function updateDarknodeDeregisteredAt(address darknodeID, uint256 deregisteredAt) external onlyOwner { darknodeRegistry[darknodeID].deregisteredAt = deregisteredAt; } /// @notice Returns the owner of a given darknode. function darknodeOwner(address darknodeID) external view onlyOwner returns (address) { return darknodeRegistry[darknodeID].owner; } /// @notice Returns the bond of a given darknode. function darknodeBond(address darknodeID) external view onlyOwner returns (uint256) { return darknodeRegistry[darknodeID].bond; } /// @notice Returns the registration time of a given darknode. function darknodeRegisteredAt(address darknodeID) external view onlyOwner returns (uint256) { return darknodeRegistry[darknodeID].registeredAt; } /// @notice Returns the deregistration time of a given darknode. function darknodeDeregisteredAt(address darknodeID) external view onlyOwner returns (uint256) { return darknodeRegistry[darknodeID].deregisteredAt; } /// @notice Returns the encryption public key of a given darknode. function darknodePublicKey(address darknodeID) external view onlyOwner returns (bytes) { return darknodeRegistry[darknodeID].publicKey; } } /// @notice DarknodeRegistry is responsible for the registration and /// deregistration of Darknodes. contract DarknodeRegistry is Ownable { string public VERSION; // Passed in as a constructor parameter. /// @notice Darknode pods are shuffled after a fixed number of blocks. /// An Epoch stores an epoch hash used as an (insecure) RNG seed, and the /// blocknumber which restricts when the next epoch can be called. struct Epoch { uint256 epochhash; uint256 blocknumber; } uint256 public numDarknodes; uint256 public numDarknodesNextEpoch; uint256 public numDarknodesPreviousEpoch; /// Variables used to parameterize behavior. uint256 public minimumBond; uint256 public minimumPodSize; uint256 public minimumEpochInterval; address public slasher; /// When one of the above variables is modified, it is only updated when the /// next epoch is called. These variables store the values for the next epoch. uint256 public nextMinimumBond; uint256 public nextMinimumPodSize; uint256 public nextMinimumEpochInterval; address public nextSlasher; /// The current and previous epoch Epoch public currentEpoch; Epoch public previousEpoch; /// Republic ERC20 token contract used to transfer bonds. RepublicToken public ren; /// Darknode Registry Store is the storage contract for darknodes. DarknodeRegistryStore public store; /// @notice Emitted when a darknode is registered. /// @param _darknodeID The darknode ID that was registered. /// @param _bond The amount of REN that was transferred as bond. event LogDarknodeRegistered(address _darknodeID, uint256 _bond); /// @notice Emitted when a darknode is deregistered. /// @param _darknodeID The darknode ID that was deregistered. event LogDarknodeDeregistered(address _darknodeID); /// @notice Emitted when a refund has been made. /// @param _owner The address that was refunded. /// @param _amount The amount of REN that was refunded. event LogDarknodeOwnerRefunded(address _owner, uint256 _amount); /// @notice Emitted when a new epoch has begun. event LogNewEpoch(); /// @notice Emitted when a constructor parameter has been updated. event LogMinimumBondUpdated(uint256 previousMinimumBond, uint256 nextMinimumBond); event LogMinimumPodSizeUpdated(uint256 previousMinimumPodSize, uint256 nextMinimumPodSize); event LogMinimumEpochIntervalUpdated(uint256 previousMinimumEpochInterval, uint256 nextMinimumEpochInterval); event LogSlasherUpdated(address previousSlasher, address nextSlasher); /// @notice Only allow the owner that registered the darknode to pass. modifier onlyDarknodeOwner(address _darknodeID) { require(store.darknodeOwner(_darknodeID) == msg.sender, "must be darknode owner"); _; } /// @notice Only allow unregistered darknodes. modifier onlyRefunded(address _darknodeID) { require(isRefunded(_darknodeID), "must be refunded or never registered"); _; } /// @notice Only allow refundable darknodes. modifier onlyRefundable(address _darknodeID) { require(isRefundable(_darknodeID), "must be deregistered for at least one epoch"); _; } /// @notice Only allowed registered nodes without a pending deregistration to /// deregister modifier onlyDeregisterable(address _darknodeID) { require(isDeregisterable(_darknodeID), "must be deregisterable"); _; } /// @notice Only allow the Slasher contract. modifier onlySlasher() { require(slasher == msg.sender, "must be slasher"); _; } /// @notice The contract constructor. /// /// @param _VERSION A string defining the contract version. /// @param _renAddress The address of the RepublicToken contract. /// @param _storeAddress The address of the DarknodeRegistryStore contract. /// @param _minimumBond The minimum bond amount that can be submitted by a /// Darknode. /// @param _minimumPodSize The minimum size of a Darknode pod. /// @param _minimumEpochInterval The minimum number of blocks between /// epochs. constructor( string _VERSION, RepublicToken _renAddress, DarknodeRegistryStore _storeAddress, uint256 _minimumBond, uint256 _minimumPodSize, uint256 _minimumEpochInterval ) public { VERSION = _VERSION; store = _storeAddress; ren = _renAddress; minimumBond = _minimumBond; nextMinimumBond = minimumBond; minimumPodSize = _minimumPodSize; nextMinimumPodSize = minimumPodSize; minimumEpochInterval = _minimumEpochInterval; nextMinimumEpochInterval = minimumEpochInterval; currentEpoch = Epoch({ epochhash: uint256(blockhash(block.number - 1)), blocknumber: block.number }); numDarknodes = 0; numDarknodesNextEpoch = 0; numDarknodesPreviousEpoch = 0; } /// @notice Register a darknode and transfer the bond to this contract. The /// caller must provide a public encryption key for the darknode as well as /// a bond in REN. The bond must be provided as an ERC20 allowance. The dark /// node will remain pending registration until the next epoch. Only after /// this period can the darknode be deregistered. The caller of this method /// will be stored as the owner of the darknode. /// /// @param _darknodeID The darknode ID that will be registered. /// @param _publicKey The public key of the darknode. It is stored to allow /// other darknodes and traders to encrypt messages to the trader. /// @param _bond The bond that will be paid. It must be greater than, or /// equal to, the minimum bond. function register(address _darknodeID, bytes _publicKey, uint256 _bond) external onlyRefunded(_darknodeID) { // REN allowance require(_bond >= minimumBond, "insufficient bond"); // require(ren.allowance(msg.sender, address(this)) >= _bond); require(ren.transferFrom(msg.sender, address(this), _bond), "bond transfer failed"); ren.transfer(address(store), _bond); // Flag this darknode for registration store.appendDarknode( _darknodeID, msg.sender, _bond, _publicKey, currentEpoch.blocknumber + minimumEpochInterval, 0 ); numDarknodesNextEpoch += 1; // Emit an event. emit LogDarknodeRegistered(_darknodeID, _bond); } /// @notice Deregister a darknode. The darknode will not be deregistered /// until the end of the epoch. After another epoch, the bond can be /// refunded by calling the refund method. /// @param _darknodeID The darknode ID that will be deregistered. The caller /// of this method store.darknodeRegisteredAt(_darknodeID) must be // the owner of this darknode. function deregister(address _darknodeID) external onlyDeregisterable(_darknodeID) onlyDarknodeOwner(_darknodeID) { // Flag the darknode for deregistration store.updateDarknodeDeregisteredAt(_darknodeID, currentEpoch.blocknumber + minimumEpochInterval); numDarknodesNextEpoch -= 1; // Emit an event emit LogDarknodeDeregistered(_darknodeID); } /// @notice Progress the epoch if it is possible to do so. This captures /// the current timestamp and current blockhash and overrides the current /// epoch. function epoch() external { if (previousEpoch.blocknumber == 0) { // The first epoch must be called by the owner of the contract require(msg.sender == owner, "not authorized (first epochs)"); } // Require that the epoch interval has passed require(block.number >= currentEpoch.blocknumber + minimumEpochInterval, "epoch interval has not passed"); uint256 epochhash = uint256(blockhash(block.number - 1)); // Update the epoch hash and timestamp previousEpoch = currentEpoch; currentEpoch = Epoch({ epochhash: epochhash, blocknumber: block.number }); // Update the registry information numDarknodesPreviousEpoch = numDarknodes; numDarknodes = numDarknodesNextEpoch; // If any update functions have been called, update the values now if (nextMinimumBond != minimumBond) { minimumBond = nextMinimumBond; emit LogMinimumBondUpdated(minimumBond, nextMinimumBond); } if (nextMinimumPodSize != minimumPodSize) { minimumPodSize = nextMinimumPodSize; emit LogMinimumPodSizeUpdated(minimumPodSize, nextMinimumPodSize); } if (nextMinimumEpochInterval != minimumEpochInterval) { minimumEpochInterval = nextMinimumEpochInterval; emit LogMinimumEpochIntervalUpdated(minimumEpochInterval, nextMinimumEpochInterval); } if (nextSlasher != slasher) { slasher = nextSlasher; emit LogSlasherUpdated(slasher, nextSlasher); } // Emit an event emit LogNewEpoch(); } /// @notice Allows the contract owner to transfer ownership of the /// DarknodeRegistryStore. /// @param _newOwner The address to transfer the ownership to. function transferStoreOwnership(address _newOwner) external onlyOwner { store.transferOwnership(_newOwner); } /// @notice Allows the contract owner to update the minimum bond. /// @param _nextMinimumBond The minimum bond amount that can be submitted by /// a darknode. function updateMinimumBond(uint256 _nextMinimumBond) external onlyOwner { // Will be updated next epoch nextMinimumBond = _nextMinimumBond; } /// @notice Allows the contract owner to update the minimum pod size. /// @param _nextMinimumPodSize The minimum size of a pod. function updateMinimumPodSize(uint256 _nextMinimumPodSize) external onlyOwner { // Will be updated next epoch nextMinimumPodSize = _nextMinimumPodSize; } /// @notice Allows the contract owner to update the minimum epoch interval. /// @param _nextMinimumEpochInterval The minimum number of blocks between epochs. function updateMinimumEpochInterval(uint256 _nextMinimumEpochInterval) external onlyOwner { // Will be updated next epoch nextMinimumEpochInterval = _nextMinimumEpochInterval; } /// @notice Allow the contract owner to update the DarknodeSlasher contract /// address. /// @param _slasher The new slasher address. function updateSlasher(address _slasher) external onlyOwner { nextSlasher = _slasher; } /// @notice Allow the DarknodeSlasher contract to slash half of a darknode's /// bond and deregister it. The bond is distributed as follows: /// 1/2 is kept by the guilty prover /// 1/8 is rewarded to the first challenger /// 1/8 is rewarded to the second challenger /// 1/4 becomes unassigned /// @param _prover The guilty prover whose bond is being slashed /// @param _challenger1 The first of the two darknodes who submitted the challenge /// @param _challenger2 The second of the two darknodes who submitted the challenge function slash(address _prover, address _challenger1, address _challenger2) external onlySlasher { uint256 penalty = store.darknodeBond(_prover) / 2; uint256 reward = penalty / 4; // Slash the bond of the failed prover in half store.updateDarknodeBond(_prover, penalty); // If the darknode has not been deregistered then deregister it if (isDeregisterable(_prover)) { store.updateDarknodeDeregisteredAt(_prover, currentEpoch.blocknumber + minimumEpochInterval); numDarknodesNextEpoch -= 1; emit LogDarknodeDeregistered(_prover); } // Reward the challengers with less than the penalty so that it is not // worth challenging yourself ren.transfer(store.darknodeOwner(_challenger1), reward); ren.transfer(store.darknodeOwner(_challenger2), reward); } /// @notice Refund the bond of a deregistered darknode. This will make the /// darknode available for registration again. Anyone can call this function /// but the bond will always be refunded to the darknode owner. /// /// @param _darknodeID The darknode ID that will be refunded. The caller /// of this method must be the owner of this darknode. function refund(address _darknodeID) external onlyRefundable(_darknodeID) { address darknodeOwner = store.darknodeOwner(_darknodeID); // Remember the bond amount uint256 amount = store.darknodeBond(_darknodeID); // Erase the darknode from the registry store.removeDarknode(_darknodeID); // Refund the owner by transferring REN ren.transfer(darknodeOwner, amount); // Emit an event. emit LogDarknodeOwnerRefunded(darknodeOwner, amount); } /// @notice Retrieves the address of the account that registered a darknode. /// @param _darknodeID The ID of the darknode to retrieve the owner for. function getDarknodeOwner(address _darknodeID) external view returns (address) { return store.darknodeOwner(_darknodeID); } /// @notice Retrieves the bond amount of a darknode in 10^-18 REN. /// @param _darknodeID The ID of the darknode to retrieve the bond for. function getDarknodeBond(address _darknodeID) external view returns (uint256) { return store.darknodeBond(_darknodeID); } /// @notice Retrieves the encryption public key of the darknode. /// @param _darknodeID The ID of the darknode to retrieve the public key for. function getDarknodePublicKey(address _darknodeID) external view returns (bytes) { return store.darknodePublicKey(_darknodeID); } /// @notice Retrieves a list of darknodes which are registered for the /// current epoch. /// @param _start A darknode ID used as an offset for the list. If _start is /// 0x0, the first dark node will be used. _start won't be /// included it is not registered for the epoch. /// @param _count The number of darknodes to retrieve starting from _start. /// If _count is 0, all of the darknodes from _start are /// retrieved. If _count is more than the remaining number of /// registered darknodes, the rest of the list will contain /// 0x0s. function getDarknodes(address _start, uint256 _count) external view returns (address[]) { uint256 count = _count; if (count == 0) { count = numDarknodes; } return getDarknodesFromEpochs(_start, count, false); } /// @notice Retrieves a list of darknodes which were registered for the /// previous epoch. See `getDarknodes` for the parameter documentation. function getPreviousDarknodes(address _start, uint256 _count) external view returns (address[]) { uint256 count = _count; if (count == 0) { count = numDarknodesPreviousEpoch; } return getDarknodesFromEpochs(_start, count, true); } /// @notice Returns whether a darknode is scheduled to become registered /// at next epoch. /// @param _darknodeID The ID of the darknode to return function isPendingRegistration(address _darknodeID) external view returns (bool) { uint256 registeredAt = store.darknodeRegisteredAt(_darknodeID); return registeredAt != 0 && registeredAt > currentEpoch.blocknumber; } /// @notice Returns if a darknode is in the pending deregistered state. In /// this state a darknode is still considered registered. function isPendingDeregistration(address _darknodeID) external view returns (bool) { uint256 deregisteredAt = store.darknodeDeregisteredAt(_darknodeID); return deregisteredAt != 0 && deregisteredAt > currentEpoch.blocknumber; } /// @notice Returns if a darknode is in the deregistered state. function isDeregistered(address _darknodeID) public view returns (bool) { uint256 deregisteredAt = store.darknodeDeregisteredAt(_darknodeID); return deregisteredAt != 0 && deregisteredAt <= currentEpoch.blocknumber; } /// @notice Returns if a darknode can be deregistered. This is true if the /// darknodes is in the registered state and has not attempted to /// deregister yet. function isDeregisterable(address _darknodeID) public view returns (bool) { uint256 deregisteredAt = store.darknodeDeregisteredAt(_darknodeID); // The Darknode is currently in the registered state and has not been // transitioned to the pending deregistration, or deregistered, state return isRegistered(_darknodeID) && deregisteredAt == 0; } /// @notice Returns if a darknode is in the refunded state. This is true /// for darknodes that have never been registered, or darknodes that have /// been deregistered and refunded. function isRefunded(address _darknodeID) public view returns (bool) { uint256 registeredAt = store.darknodeRegisteredAt(_darknodeID); uint256 deregisteredAt = store.darknodeDeregisteredAt(_darknodeID); return registeredAt == 0 && deregisteredAt == 0; } /// @notice Returns if a darknode is refundable. This is true for darknodes /// that have been in the deregistered state for one full epoch. function isRefundable(address _darknodeID) public view returns (bool) { return isDeregistered(_darknodeID) && store.darknodeDeregisteredAt(_darknodeID) <= previousEpoch.blocknumber; } /// @notice Returns if a darknode is in the registered state. function isRegistered(address _darknodeID) public view returns (bool) { return isRegisteredInEpoch(_darknodeID, currentEpoch); } /// @notice Returns if a darknode was in the registered state last epoch. function isRegisteredInPreviousEpoch(address _darknodeID) public view returns (bool) { return isRegisteredInEpoch(_darknodeID, previousEpoch); } /// @notice Returns if a darknode was in the registered state for a given /// epoch. /// @param _darknodeID The ID of the darknode /// @param _epoch One of currentEpoch, previousEpoch function isRegisteredInEpoch(address _darknodeID, Epoch _epoch) private view returns (bool) { uint256 registeredAt = store.darknodeRegisteredAt(_darknodeID); uint256 deregisteredAt = store.darknodeDeregisteredAt(_darknodeID); bool registered = registeredAt != 0 && registeredAt <= _epoch.blocknumber; bool notDeregistered = deregisteredAt == 0 || deregisteredAt > _epoch.blocknumber; // The Darknode has been registered and has not yet been deregistered, // although it might be pending deregistration return registered && notDeregistered; } /// @notice Returns a list of darknodes registered for either the current /// or the previous epoch. See `getDarknodes` for documentation on the /// parameters `_start` and `_count`. /// @param _usePreviousEpoch If true, use the previous epoch, otherwise use /// the current epoch. function getDarknodesFromEpochs(address _start, uint256 _count, bool _usePreviousEpoch) private view returns (address[]) { uint256 count = _count; if (count == 0) { count = numDarknodes; } address[] memory nodes = new address[](count); // Begin with the first node in the list uint256 n = 0; address next = _start; if (next == 0x0) { next = store.begin(); } // Iterate until all registered Darknodes have been collected while (n < count) { if (next == 0x0) { break; } // Only include Darknodes that are currently registered bool includeNext; if (_usePreviousEpoch) { includeNext = isRegisteredInPreviousEpoch(next); } else { includeNext = isRegistered(next); } if (!includeNext) { next = store.next(next); continue; } nodes[n] = next; next = store.next(next); n += 1; } return nodes; } } /** * @title Math * @dev Assorted math operations */ library Math { function max64(uint64 a, uint64 b) internal pure returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal pure returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } } /// @notice Implements safeTransfer, safeTransferFrom and /// safeApprove for CompatibleERC20. /// /// See https://github.com/ethereum/solidity/issues/4116 /// /// This library allows interacting with ERC20 tokens that implement any of /// these interfaces: /// /// (1) transfer returns true on success, false on failure /// (2) transfer returns true on success, reverts on failure /// (3) transfer returns nothing on success, reverts on failure /// /// Additionally, safeTransferFromWithFees will return the final token /// value received after accounting for token fees. library CompatibleERC20Functions { using SafeMath for uint256; /// @notice Calls transfer on the token and reverts if the call fails. function safeTransfer(address token, address to, uint256 amount) internal { CompatibleERC20(token).transfer(to, amount); require(previousReturnValue(), "transfer failed"); } /// @notice Calls transferFrom on the token and reverts if the call fails. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { CompatibleERC20(token).transferFrom(from, to, amount); require(previousReturnValue(), "transferFrom failed"); } /// @notice Calls approve on the token and reverts if the call fails. function safeApprove(address token, address spender, uint256 amount) internal { CompatibleERC20(token).approve(spender, amount); require(previousReturnValue(), "approve failed"); } /// @notice Calls transferFrom on the token, reverts if the call fails and /// returns the value transferred after fees. function safeTransferFromWithFees(address token, address from, address to, uint256 amount) internal returns (uint256) { uint256 balancesBefore = CompatibleERC20(token).balanceOf(to); CompatibleERC20(token).transferFrom(from, to, amount); require(previousReturnValue(), "transferFrom failed"); uint256 balancesAfter = CompatibleERC20(token).balanceOf(to); return Math.min256(amount, balancesAfter.sub(balancesBefore)); } /// @notice Checks the return value of the previous function. Returns true /// if the previous function returned 32 non-zero bytes or returned zero /// bytes. function previousReturnValue() private pure returns (bool) { uint256 returnData = 0; assembly { /* solium-disable-line security/no-inline-assembly */ // Switch on the number of bytes returned by the previous call switch returndatasize // 0 bytes: ERC20 of type (3), did not throw case 0 { returnData := 1 } // 32 bytes: ERC20 of types (1) or (2) case 32 { // Copy the return data into scratch space returndatacopy(0x0, 0x0, 32) // Load the return data into returnData returnData := mload(0x0) } // Other return size: return false default { } } return returnData != 0; } } /// @notice ERC20 interface which doesn't specify the return type for transfer, /// transferFrom and approve. interface CompatibleERC20 { // Modified to not return boolean function transfer(address to, uint256 value) external; function transferFrom(address from, address to, uint256 value) external; function approve(address spender, uint256 value) external; // Not modifier 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); } /// @notice The DarknodeRewardVault contract is responsible for holding fees /// for darknodes for settling orders. Fees can be withdrawn to the address of /// the darknode's operator. Fees can be in ETH or in ERC20 tokens. /// Docs: https://github.com/republicprotocol/republic-sol/blob/master/docs/02-darknode-reward-vault.md contract DarknodeRewardVault is Ownable { using SafeMath for uint256; using CompatibleERC20Functions for CompatibleERC20; string public VERSION; // Passed in as a constructor parameter. /// @notice The special address for Ether. address constant public ETHEREUM = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; DarknodeRegistry public darknodeRegistry; mapping(address => mapping(address => uint256)) public darknodeBalances; event LogDarknodeRegistryUpdated(DarknodeRegistry previousDarknodeRegistry, DarknodeRegistry nextDarknodeRegistry); /// @notice The contract constructor. /// /// @param _VERSION A string defining the contract version. /// @param _darknodeRegistry The DarknodeRegistry contract that is used by /// the vault to lookup Darknode owners. constructor(string _VERSION, DarknodeRegistry _darknodeRegistry) public { VERSION = _VERSION; darknodeRegistry = _darknodeRegistry; } function updateDarknodeRegistry(DarknodeRegistry _newDarknodeRegistry) public onlyOwner { emit LogDarknodeRegistryUpdated(darknodeRegistry, _newDarknodeRegistry); darknodeRegistry = _newDarknodeRegistry; } /// @notice Deposit fees into the vault for a Darknode. The Darknode /// registration is not checked (to reduce gas fees); the caller must be /// careful not to call this function for a Darknode that is not registered /// otherwise any fees deposited to that Darknode can be withdrawn by a /// malicious adversary (by registering the Darknode before the honest /// party and claiming ownership). /// /// @param _darknode The address of the Darknode that will receive the /// fees. /// @param _token The address of the ERC20 token being used to pay the fee. /// A special address is used for Ether. /// @param _value The amount of fees in the smallest unit of the token. function deposit(address _darknode, ERC20 _token, uint256 _value) public payable { uint256 receivedValue = _value; if (address(_token) == ETHEREUM) { require(msg.value == _value, "mismatched ether value"); } else { require(msg.value == 0, "unexpected ether value"); receivedValue = CompatibleERC20(_token).safeTransferFromWithFees(msg.sender, address(this), _value); } darknodeBalances[_darknode][_token] = darknodeBalances[_darknode][_token].add(receivedValue); } /// @notice Withdraw fees earned by a Darknode. The fees will be sent to /// the owner of the Darknode. If a Darknode is not registered the fees /// cannot be withdrawn. /// /// @param _darknode The address of the Darknode whose fees are being /// withdrawn. The owner of this Darknode will receive the fees. /// @param _token The address of the ERC20 token to withdraw. function withdraw(address _darknode, ERC20 _token) public { address darknodeOwner = darknodeRegistry.getDarknodeOwner(address(_darknode)); require(darknodeOwner != 0x0, "invalid darknode owner"); uint256 value = darknodeBalances[_darknode][_token]; darknodeBalances[_darknode][_token] = 0; if (address(_token) == ETHEREUM) { darknodeOwner.transfer(value); } else { CompatibleERC20(_token).safeTransfer(darknodeOwner, value); } } }
Contract ABI
[{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"darknodeBalances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_darknode","type":"address"},{"name":"_token","type":"address"},{"name":"_value","type":"uint256"}],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"darknodeRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDarknodeRegistry","type":"address"}],"name":"updateDarknodeRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ETHEREUM","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_darknode","type":"address"},{"name":"_token","type":"address"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"VERSION","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_VERSION","type":"string"},{"name":"_darknodeRegistry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousDarknodeRegistry","type":"address"},{"indexed":false,"name":"nextDarknodeRegistry","type":"address"}],"name":"LogDarknodeRegistryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620015af380380620015af8339810180604052810190808051820192919060200180519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600190805190602001906200009b929190620000e5565b5080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505062000194565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200012857805160ff191683800117855562000159565b8280016001018555821562000159579182015b82811115620001585782518255916020019190600101906200013b565b5b5090506200016891906200016c565b5090565b6200019191905b808211156200018d57600081600090555060010162000173565b5090565b90565b61140b80620001a46000396000f3006080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806370324b77146100a9578063715018a6146101205780638340f549146101375780638da5cb5b146101975780639e45e0d0146101ee578063aaff096d14610245578063f2fde38b14610288578063f7cdf47c146102cb578063f940e38514610322578063ffa1ad7414610385575b600080fd5b3480156100b557600080fd5b5061010a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610415565b6040518082815260200191505060405180910390f35b34801561012c57600080fd5b5061013561043a565b005b610195600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061053c565b005b3480156101a357600080fd5b506101ac6107c2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101fa57600080fd5b506102036107e7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561025157600080fd5b50610286600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061080d565b005b34801561029457600080fd5b506102c9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610965565b005b3480156102d757600080fd5b506102e06109cc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561032e57600080fd5b50610383600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109e4565b005b34801561039157600080fd5b5061039a610d37565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103da5780820151818401526020810190506103bf565b50505050905090810190601f1680156104075780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6003602052816000526040600020602052806000526040600020600091509150505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561049557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167ff8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c6482060405160405180910390a260008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600081905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610605578134141515610600576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f6d69736d6174636865642065746865722076616c75650000000000000000000081525060200191505060405180910390fd5b6106ad565b60003414151561067d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f756e65787065637465642065746865722076616c75650000000000000000000081525060200191505060405180910390fd5b6106aa3330848673ffffffffffffffffffffffffffffffffffffffff16610dd5909392919063ffffffff16565b90505b61073c81600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461111d90919063ffffffff16565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561086857600080fd5b7ff9f6dd5c784f63cc27c1079c73574a73485a6c2e7f7e2181c5eb2be8c693cfb7600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a180600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109c057600080fd5b6109c981611139565b50565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b600080600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631cedf8a3856040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610aa457600080fd5b505af1158015610ab8573d6000803e3d6000fd5b505050506040513d6020811015610ace57600080fd5b8101908080519060200190929190505050915060008273ffffffffffffffffffffffffffffffffffffffff1614151515610b70576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f696e76616c6964206461726b6e6f6465206f776e65720000000000000000000081525060200191505060405180910390fd5b600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610d05578173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610cff573d6000803e3d6000fd5b50610d31565b610d3082828573ffffffffffffffffffffffffffffffffffffffff166112339092919063ffffffff16565b5b50505050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610dcd5780601f10610da257610100808354040283529160200191610dcd565b820191906000526020600020905b815481529060010190602001808311610db057829003601f168201915b505050505081565b60008060008673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506040513d6020811015610e9f57600080fd5b810190808051906020019092919050505091508673ffffffffffffffffffffffffffffffffffffffff166323b872dd8787876040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015610f8957600080fd5b505af1158015610f9d573d6000803e3d6000fd5b50505050610fa961136f565b151561101d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f7472616e7366657246726f6d206661696c65640000000000000000000000000081525060200191505060405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156110b857600080fd5b505af11580156110cc573d6000803e3d6000fd5b505050506040513d60208110156110e257600080fd5b810190808051906020019092919050505090506111118461110c84846113ad90919063ffffffff16565b6113c6565b92505050949350505050565b6000818301905082811015151561113057fe5b80905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561117557600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156112d657600080fd5b505af11580156112ea573d6000803e3d6000fd5b505050506112f661136f565b151561136a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f7472616e73666572206661696c6564000000000000000000000000000000000081525060200191505060405180910390fd5b505050565b600080600090503d6000811461138c5760208114611395576113a1565b600191506113a1565b60206000803e60005191505b50600081141591505090565b60008282111515156113bb57fe5b818303905092915050565b60008183106113d557816113d7565b825b9050929150505600a165627a7a7230582039fb41d820a376d002935ea4d6a98845cf625c91279852ff84273ff39b54d0d10029000000000000000000000000000000000000000000000000000000000000004000000000000000000000000034bd421c7948bc16f826fd99f9b785929b1216330000000000000000000000000000000000000000000000000000000000000005312e302e32000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000004000000000000000000000000034bd421c7948bc16f826fd99f9b785929b1216330000000000000000000000000000000000000000000000000000000000000005312e302e32000000000000000000000000000000000000000000000000000000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 00000000000000000000000034bd421c7948bc16f826fd99f9b785929b121633
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [3] : 312e302e32000000000000000000000000000000000000000000000000000000
Swarm Source:
bzzr://39fb41d820a376d002935ea4d6a98845cf625c91279852ff84273ff39b54d0d1
Block | Age | transaction | Difficulty | GasUsed | Reward |
---|
Block | Age | Uncle Number | Difficulty | GasUsed | Reward |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.