Transaction Hash:
Block:
13566596 at Nov-07-2021 01:59:25 AM +UTC
Transaction Fee:
0.016106685276959604 ETH
$30.24
Gas Used:
190,396 Gas / 84.595712499 Gwei
Emitted Events:
162 |
TokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000513fb60037240205a0cf17c260257097d747bd46, 0x00000000000000000000000013aa17dc704f634a9c897689fff86ac302d3cc38, 0000000000000000000000000000000000000000000000679da9454f19568a6d )
|
163 |
RewardDelegatorsProxy.0x643d0f768d20758fe82686d7de201866faaee92f36542c9b1ea68fe26217dc90( 0x643d0f768d20758fe82686d7de201866faaee92f36542c9b1ea68fe26217dc90, 00000000000000000000000013aa17dc704f634a9c897689fff86ac302d3cc38 )
|
164 |
TokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000513fb60037240205a0cf17c260257097d747bd46, 0x00000000000000000000000084b9eee80beb6e618d677343c6eff6f3240326e7, 0000000000000000000000000000000000000000000002ee0aaad352e75f9f77 )
|
165 |
RewardDelegatorsProxy.0x54e8f034636217314f27bfc2c4e0aec174ceab3a2b1196d2e00f8bae09ac52fd( 0x54e8f034636217314f27bfc2c4e0aec174ceab3a2b1196d2e00f8bae09ac52fd, 00000000000000000000000013aa17dc704f634a9c897689fff86ac302d3cc38, 00000000000000000000000084b9eee80beb6e618d677343c6eff6f3240326e7, 0000000000000000000000000000000000000000000000000000000000000080, 0000000000000000000000000000000000000000000002ee0aaad352e75f9f77, 0000000000000000000000000000000000000000000000000000000000000002, 5802add45f8ec0a524470683e7295faacc853f97cf4a8d3ffbaaf25ce0fd87c4, 1635815984abab0dbb9afd77984dad69c24bf3d711bc0ddb1e2d53ef2d523e5e )
|
166 |
StakeManagerProxy.0x910aaad05eef8babc75a5bbd3987092b49f6dcd0fd06c860d9af177b650c5625( 0x910aaad05eef8babc75a5bbd3987092b49f6dcd0fd06c860d9af177b650c5625, 363a63c83fb1b082d2626fb079e7d74d92caf27fec08dcc75278f5de8d9db6d7, 00000000000000000000000013aa17dc704f634a9c897689fff86ac302d3cc38, 0000000000000000000000000000000000000000000000000000000000cfb634 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1aD91ee0...dA6B45836
Miner
| (Hiveon Pool) | 7,880.891331917973092816 Eth | 7,880.891617511973092816 Eth | 0.000285594 | |
0x5124324e...Ef0297cd7 | |||||
0x513FB600...7D747BD46 | |||||
0x57B94600...10e58D26C | |||||
0x84b9eee8...3240326E7 |
0.467937084219774429 Eth
Nonce: 273
|
0.451830398942814825 Eth
Nonce: 274
| 0.016106685276959604 | ||
0xCBB94D13...8ae4B6c82 | (Marlin: Stake Manager Proxy) |
Execution Trace
StakeManagerProxy.5dc47b57( )
StakeManager.undelegateStash( _stashId=363A63C83FB1B082D2626FB079E7D74D92CAF27FEC08DCC75278F5DE8D9DB6D7 )
RewardDelegatorsProxy.STATICCALL( )
-
RewardDelegators.DELEGATECALL( )
-
RewardDelegatorsProxy.9a943e00( )
RewardDelegators.undelegate( )
ClusterRewardsProxy.d279c191( )
-
ClusterRewards.claimReward( _cluster=0x13aa17dc704f634a9C897689FfF86ac302d3cc38 ) => ( 47784383183328310953132 )
-
ClusterRegistryProxy.06032d74( )
-
ClusterRegistry.getRewardInfo( _cluster=0x13aa17dc704f634a9C897689FfF86ac302d3cc38 ) => ( 4, 0x13aa17dc704f634a9C897689FfF86ac302d3cc38 )
-
TokenProxy.a9059cbb( )
-
TokenLogic.transfer( to=0x13aa17dc704f634a9C897689FfF86ac302d3cc38, value=1911375327333132438125 ) => ( True )
-
TokenProxy.a9059cbb( )
-
TokenLogic.transfer( to=0x84b9eee80BeB6e618d677343C6eFF6f3240326E7, value=13835826714321606385527 ) => ( True )
-
undelegateStash[StakeManager (ln:1828)]
add[StakeManager (ln:1839)]
_cancelRedelegation[StakeManager (ln:1842)]
RedelegationCancelled[StakeManager (ln:1822)]
getFullTokenList[StakeManager (ln:1843)]
undelegate[StakeManager (ln:1848)]
StashUndelegated[StakeManager (ln:1849)]
File 1 of 10: StakeManagerProxy
File 2 of 10: TokenProxy
File 3 of 10: RewardDelegatorsProxy
File 4 of 10: StakeManager
File 5 of 10: RewardDelegators
File 6 of 10: ClusterRewardsProxy
File 7 of 10: ClusterRewards
File 8 of 10: ClusterRegistryProxy
File 9 of 10: ClusterRegistry
File 10 of 10: TokenLogic
pragma solidity >=0.4.21 <0.7.0; /// @title Contract to reward overlapping stakes /// @author Marlin /// @notice Use this contract only for testing /// @dev Contract may or may not change in future (depending upon the new slots in proxy-store) contract StakeManagerProxy { bytes32 internal constant IMPLEMENTATION_SLOT = bytes32( uint256(keccak256("eip1967.proxy.implementation")) - 1 ); bytes32 internal constant PROXY_ADMIN_SLOT = bytes32( uint256(keccak256("eip1967.proxy.admin")) - 1 ); constructor(address contractLogic, address proxyAdmin) public { // save the code address bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, contractLogic) } // save the proxy admin slot = PROXY_ADMIN_SLOT; address sender = proxyAdmin; assembly { sstore(slot, sender) } } function updateAdmin(address _newAdmin) public { require( msg.sender == getAdmin(), "Only the current admin should be able to new admin" ); bytes32 slot = PROXY_ADMIN_SLOT; assembly { sstore(slot, _newAdmin) } } /// @author Marlin /// @dev Only admin can update the contract /// @param _newLogic address is the address of the contract that has to updated to function updateLogic(address _newLogic) public { require( msg.sender == getAdmin(), "Only Admin should be able to update the contracts" ); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, _newLogic) } } /// @author Marlin /// @dev use assembly as contract store slot is manually decided function getAdmin() internal view returns (address result) { bytes32 slot = PROXY_ADMIN_SLOT; assembly { result := sload(slot) } } /// @author Marlin /// @dev add functionality to forward the balance as well. function() external payable { bytes32 slot = IMPLEMENTATION_SLOT; assembly { let contractLogic := sload(slot) calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } }
File 2 of 10: TokenProxy
pragma solidity >=0.4.21 <0.7.0; /// @title Contract to reward overlapping stakes /// @author Marlin /// @notice Use this contract only for testing /// @dev Contract may or may not change in future (depending upon the new slots in proxy-store) contract TokenProxy { bytes32 internal constant IMPLEMENTATION_SLOT = bytes32( uint256(keccak256("eip1967.proxy.implementation")) - 1 ); bytes32 internal constant PROXY_ADMIN_SLOT = bytes32( uint256(keccak256("eip1967.proxy.admin")) - 1 ); constructor(address contractLogic, address proxyAdmin) public { // save the code address bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, contractLogic) } // save the proxy admin slot = PROXY_ADMIN_SLOT; address sender = proxyAdmin; assembly { sstore(slot, sender) } } function updateAdmin(address _newAdmin) public { require( msg.sender == getAdmin(), "Only the current admin should be able to new admin" ); bytes32 slot = PROXY_ADMIN_SLOT; assembly { sstore(slot, _newAdmin) } } /// @author Marlin /// @dev Only admin can update the contract /// @param _newLogic address is the address of the contract that has to updated to function updateLogic(address _newLogic) public { require( msg.sender == getAdmin(), "Only Admin should be able to update the contracts" ); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, _newLogic) } } /// @author Marlin /// @dev use assembly as contract store slot is manually decided function getAdmin() internal view returns (address result) { bytes32 slot = PROXY_ADMIN_SLOT; assembly { result := sload(slot) } } /// @author Marlin /// @dev add functionality to forward the balance as well. function() external payable { bytes32 slot = IMPLEMENTATION_SLOT; assembly { let contractLogic := sload(slot) calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } }
File 3 of 10: RewardDelegatorsProxy
pragma solidity >=0.4.21 <0.7.0; /// @title Contract to reward overlapping stakes /// @author Marlin /// @notice Use this contract only for testing /// @dev Contract may or may not change in future (depending upon the new slots in proxy-store) contract RewardDelegatorsProxy { bytes32 internal constant IMPLEMENTATION_SLOT = bytes32( uint256(keccak256("eip1967.proxy.implementation")) - 1 ); bytes32 internal constant PROXY_ADMIN_SLOT = bytes32( uint256(keccak256("eip1967.proxy.admin")) - 1 ); constructor(address contractLogic, address proxyAdmin) public { // save the code address bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, contractLogic) } // save the proxy admin slot = PROXY_ADMIN_SLOT; address sender = proxyAdmin; assembly { sstore(slot, sender) } } function updateAdmin(address _newAdmin) public { require( msg.sender == getAdmin(), "Only the current admin should be able to new admin" ); bytes32 slot = PROXY_ADMIN_SLOT; assembly { sstore(slot, _newAdmin) } } /// @author Marlin /// @dev Only admin can update the contract /// @param _newLogic address is the address of the contract that has to updated to function updateLogic(address _newLogic) public { require( msg.sender == getAdmin(), "Only Admin should be able to update the contracts" ); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, _newLogic) } } /// @author Marlin /// @dev use assembly as contract store slot is manually decided function getAdmin() internal view returns (address result) { bytes32 slot = PROXY_ADMIN_SLOT; assembly { result := sload(slot) } } /// @author Marlin /// @dev add functionality to forward the balance as well. function() external payable { bytes32 slot = IMPLEMENTATION_SLOT; assembly { let contractLogic := sload(slot) calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } }
File 4 of 10: StakeManager
pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * ////IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } pragma solidity 0.5.17; pragma experimental ABIEncoderV2; contract MPondLogic is Initializable { /// @notice EIP-20 token name for this token string public name; /// @notice EIP-20 token symbol for this token string public symbol; /// @notice EIP-20 token decimals for this token uint8 public decimals; /// @notice Total number of tokens in circulation uint256 public totalSupply; // 10k MPond uint256 public bridgeSupply; // 3k MPond address public dropBridge; /// @notice Allowance amounts on behalf of others mapping(address => mapping(address => uint96)) internal allowances; /// @notice Official record of token balances for each account mapping(address => uint96) internal balances; /// @notice A record of each accounts delegate mapping(address => mapping(address => uint96)) public delegates; /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint32 fromBlock; uint96 votes; } /// @notice A record of votes checkpoints for each account, by index mapping(address => mapping(uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping(address => uint32) public numCheckpoints; /// @notice The EIP-712 typehash for the contract's domain bytes32 public DOMAIN_TYPEHASH; /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public DELEGATION_TYPEHASH; /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public UNDELEGATION_TYPEHASH; /// @notice A record of states for signing / validating signatures mapping(address => uint256) public nonces; /// customized params address public admin; mapping(address => bool) public isWhiteListed; bool public enableAllTranfers; /// @notice An event thats emitted when an account changes its delegate event DelegateChanged( address indexed delegator, address indexed fromDelegate, address indexed toDelegate ); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged( address indexed delegate, uint256 previousBalance, uint256 newBalance ); /// @notice The standard EIP-20 transfer event event Transfer(address indexed from, address indexed to, uint256 amount); /// @notice The standard EIP-20 approval event event Approval( address indexed owner, address indexed spender, uint256 amount ); /** * @notice Initializer a new MPond token * @param account The initial account to grant all the tokens */ function initialize( address account, address bridge, address dropBridgeAddress ) public initializer { createConstants(); require( account != bridge, "Bridge and account should not be the same address" ); balances[bridge] = uint96(bridgeSupply); delegates[bridge][address(0)] = uint96(bridgeSupply); isWhiteListed[bridge] = true; emit Transfer(address(0), bridge, bridgeSupply); uint96 remainingSupply = sub96( uint96(totalSupply), uint96(bridgeSupply), "MPond: Subtraction overflow in the constructor" ); balances[account] = remainingSupply; delegates[account][address(0)] = remainingSupply; isWhiteListed[account] = true; dropBridge = dropBridgeAddress; emit Transfer(address(0), account, uint256(remainingSupply)); } function createConstants() internal { name = "Marlin"; symbol = "MPond"; decimals = 18; totalSupply = 10000e18; bridgeSupply = 7000e18; DOMAIN_TYPEHASH = keccak256( "EIP712Domain(string name,uint256 chainId,address verifyingContract)" ); DELEGATION_TYPEHASH = keccak256( "Delegation(address delegatee,uint256 nonce,uint256 expiry,uint96 amount)" ); UNDELEGATION_TYPEHASH = keccak256( "Unelegation(address delegatee,uint256 nonce,uint256 expiry,uint96 amount)" ); admin = msg.sender; // enableAllTranfers = true; //This is only for testing, will be false } function addWhiteListAddress(address _address) external onlyAdmin("Only admin can whitelist") returns (bool) { isWhiteListed[_address] = true; return true; } function removeWhiteListAddress(address _address) external onlyAdmin("Only admin can remove from whitelist") returns (bool) { isWhiteListed[_address] = false; return true; } function enableAllTransfers() external onlyAdmin("Only admin can enable all transfers") returns (bool) { enableAllTranfers = true; return true; } function disableAllTransfers() external onlyAdmin("Only admin can disable all transfers") returns (bool) { enableAllTranfers = false; return true; } function changeDropBridge(address _updatedBridge) public onlyAdmin("Only admin can change drop bridge") { dropBridge = _updatedBridge; } function isWhiteListedTransfer(address _address1, address _address2) public view returns (bool) { if ( enableAllTranfers || isWhiteListed[_address1] || isWhiteListed[_address2] ) { return true; } else if (_address1 == dropBridge) { return true; } return false; } /** * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` * @param account The address of the account holding the funds * @param spender The address of the account spending the funds * @return The number of tokens approved */ function allowance(address account, address spender) external view returns (uint256) { return allowances[account][spender]; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 rawAmount) external returns (bool) { uint96 amount; if (rawAmount == uint256(-1)) { amount = uint96(-1); } else { amount = safe96( rawAmount, "MPond::approve: amount exceeds 96 bits" ); } allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function increaseAllowance(address spender, uint256 addedAmount) external returns (bool) { uint96 amount; if (addedAmount == uint256(-1)) { amount = uint96(-1); } else { amount = safe96( addedAmount, "MPond::approve: addedAmount exceeds 96 bits" ); } allowances[msg.sender][spender] = add96( allowances[msg.sender][spender], amount, "MPond: increaseAllowance allowance value overflows" ); emit Approval(msg.sender, spender, allowances[msg.sender][spender]); return true; } function decreaseAllowance(address spender, uint256 removedAmount) external returns (bool) { uint96 amount; if (removedAmount == uint256(-1)) { amount = uint96(-1); } else { amount = safe96( removedAmount, "MPond::approve: removedAmount exceeds 96 bits" ); } allowances[msg.sender][spender] = sub96( allowances[msg.sender][spender], amount, "MPond: decreaseAllowance allowance value underflows" ); emit Approval(msg.sender, spender, allowances[msg.sender][spender]); return true; } /** * @notice Get the number of tokens held by the `account` * @param account The address of the account to get the balance of * @return The number of tokens held */ function balanceOf(address account) external view returns (uint256) { return balances[account]; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint256 rawAmount) external returns (bool) { require( isWhiteListedTransfer(msg.sender, dst), "Atleast one of the address (src or dst) should be whitelisted or all transfers must be enabled via enableAllTransfers()" ); uint96 amount = safe96( rawAmount, "MPond::transfer: amount exceeds 96 bits" ); _transferTokens(msg.sender, dst, amount); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom( address src, address dst, uint256 rawAmount ) external returns (bool) { require( isWhiteListedTransfer(src, dst), "Atleast one of the address (src or dst) should be whitelisted or all transfers must be enabled via enableAllTransfers()" ); address spender = msg.sender; uint96 spenderAllowance = allowances[src][spender]; uint96 amount = safe96( rawAmount, "MPond::approve: amount exceeds 96 bits" ); if (spender != src && spenderAllowance != uint96(-1)) { uint96 newAllowance = sub96( spenderAllowance, amount, "MPond::transferFrom: transfer amount exceeds spender allowance" ); allowances[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee, uint96 amount) public { return _delegate(msg.sender, delegatee, amount); } function undelegate(address delegatee, uint96 amount) public { return _undelegate(msg.sender, delegatee, amount); } /** * @notice Delegates votes from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s, uint96 amount ) public { bytes32 domainSeparator = keccak256( abi.encode( DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this) ) ); bytes32 structHash = keccak256( abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry, amount) ); bytes32 digest = keccak256( abi.encodePacked("\x19\x01", domainSeparator, structHash) ); address signatory = ecrecover(digest, v, r, s); require( signatory != address(0), "MPond::delegateBySig: invalid signature" ); require( nonce == nonces[signatory]++, "MPond::delegateBySig: invalid nonce" ); require(now <= expiry, "MPond::delegateBySig: signature expired"); return _delegate(signatory, delegatee, amount); } function undelegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s, uint96 amount ) public { bytes32 domainSeparator = keccak256( abi.encode( DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this) ) ); bytes32 structHash = keccak256( abi.encode(UNDELEGATION_TYPEHASH, delegatee, nonce, expiry, amount) ); bytes32 digest = keccak256( abi.encodePacked("\x19\x01", domainSeparator, structHash) ); address signatory = ecrecover(digest, v, r, s); require( signatory != address(0), "MPond::undelegateBySig: invalid signature" ); require( nonce == nonces[signatory]++, "MPond::undelegateBySig: invalid nonce" ); require(now <= expiry, "MPond::undelegateBySig: signature expired"); return _undelegate(signatory, delegatee, amount); } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getCurrentVotes(address account) external view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints != 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } /** * @notice Determine the prior number of votes for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param account The address of the account to check * @param blockNumber The block number to get the vote balance at * @return The number of votes the account had as of the given block */ function getPriorVotes(address account, uint256 blockNumber) public view returns (uint96) { require( blockNumber < block.number, "MPond::getPriorVotes: not yet determined" ); uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { return checkpoints[account][nCheckpoints - 1].votes; } // Next check implicit zero balance if (checkpoints[account][0].fromBlock > blockNumber) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } function _delegate( address delegator, address delegatee, uint96 amount ) internal { delegates[delegator][address(0)] = sub96( delegates[delegator][address(0)], amount, "MPond: delegates underflow" ); delegates[delegator][delegatee] = add96( delegates[delegator][delegatee], amount, "MPond: delegates overflow" ); emit DelegateChanged(delegator, address(0), delegatee); _moveDelegates(address(0), delegatee, amount); } function _undelegate( address delegator, address delegatee, uint96 amount ) internal { delegates[delegator][delegatee] = sub96( delegates[delegator][delegatee], amount, "MPond: undelegates underflow" ); delegates[delegator][address(0)] = add96( delegates[delegator][address(0)], amount, "MPond: delegates underflow" ); emit DelegateChanged(delegator, delegatee, address(0)); _moveDelegates(delegatee, address(0), amount); } function _transferTokens( address src, address dst, uint96 amount ) internal { require( src != address(0), "MPond::_transferTokens: cannot transfer from the zero address" ); require( delegates[src][address(0)] >= amount, "MPond: _transferTokens: undelegated amount should be greater than transfer amount" ); require( dst != address(0), "MPond::_transferTokens: cannot transfer to the zero address" ); balances[src] = sub96( balances[src], amount, "MPond::_transferTokens: transfer amount exceeds balance" ); delegates[src][address(0)] = sub96( delegates[src][address(0)], amount, "MPond: _tranferTokens: undelegate subtraction error" ); balances[dst] = add96( balances[dst], amount, "MPond::_transferTokens: transfer amount overflows" ); delegates[dst][address(0)] = add96( delegates[dst][address(0)], amount, "MPond: _transferTokens: undelegate addition error" ); emit Transfer(src, dst, amount); // _moveDelegates(delegates[src], delegates[dst], amount); } function _moveDelegates( address srcRep, address dstRep, uint96 amount ) internal { if (srcRep != dstRep && amount != 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint96 srcRepOld = srcRepNum != 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint96 srcRepNew = sub96( srcRepOld, amount, "MPond::_moveVotes: vote amount underflows" ); _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint96 dstRepOld = dstRepNum != 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint96 dstRepNew = add96( dstRepOld, amount, "MPond::_moveVotes: vote amount overflows" ); _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } } function _writeCheckpoint( address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes ) internal { uint32 blockNumber = safe32( block.number, "MPond::_writeCheckpoint: block number exceeds 32 bits" ); if ( nCheckpoints != 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber ) { checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { checkpoints[delegatee][nCheckpoints] = Checkpoint( blockNumber, newVotes ); numCheckpoints[delegatee] = nCheckpoints + 1; } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } function add96( uint96 a, uint96 b, string memory errorMessage ) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, errorMessage); return c; } function sub96( uint96 a, uint96 b, string memory errorMessage ) internal pure returns (uint96) { require(b <= a, errorMessage); return a - b; } function getChainId() internal pure returns (uint256) { uint256 chainId; assembly { chainId := chainid() } return chainId; } modifier onlyAdmin(string memory _error) { require(msg.sender == admin, _error); _; } } pragma solidity ^0.5.17; interface IRewardDelegators { // there's no undelegationWaitTime in rewardDelegators contract function undelegationWaitTime() external returns(uint256); function minMPONDStake() external returns(uint256); function MPONDTokenId() external returns(bytes32); function updateMPONDTokenId(bytes32 _updatedMPONDTokenId) external; function addRewardFactor(bytes32 _tokenId, uint256 _rewardFactor) external; function removeRewardFactor(bytes32 _tokenId) external; function updateRewardFactor(bytes32 _tokenId, uint256 _updatedRewardFactor) external; function _updateRewards(address _cluster) external; function delegate( address _delegator, address _cluster, bytes32[] calldata _tokens, uint256[] calldata _amounts ) external; function undelegate( address _delegator, address _cluster, bytes32[] calldata _tokens, uint256[] calldata _amounts ) external; function withdrawRewards(address _delegator, address _cluster) external returns(uint256); function isClusterActive(address _cluster) external returns(bool); function getClusterDelegation(address _cluster, bytes32 _tokenId) external view returns(uint256); function getDelegation(address _cluster, address _delegator, bytes32 _tokenId) external view returns(uint256); function updateUndelegationWaitTime(uint256 _undelegationWaitTime) external; function updateMinMPONDStake(uint256 _minMPONDStake) external; function updateStakeAddress(address _updatedStakeAddress) external; function updateClusterRewards(address _updatedClusterRewards) external; function updateClusterRegistry(address _updatedClusterRegistry) external; function updatePONDAddress(address _updatedPOND) external; function getFullTokenList() external view returns (bytes32[] memory); function getAccRewardPerShare(address _cluster, bytes32 _tokenId) external view returns(uint256); } pragma solidity ^0.5.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * > Note: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } uint256[50] private ______gap; } pragma solidity >=0.4.21 <0.7.0; contract StakeManager is Initializable, Ownable { using SafeMath for uint256; struct Stash { address staker; address delegatedCluster; mapping(bytes32 => uint256) amount; // name is not intuitive uint256 undelegatesAt; } struct Token { address addr; bool isActive; } // stashId to stash // stashId = keccak256(index) mapping(bytes32 => Stash) public stashes; // Stash index for unique id generation uint256 public stashIndex; // tokenId to token address - tokenId = keccak256(tokenTicker) mapping(bytes32 => Token) tokenAddresses; MPondLogic MPOND; MPondLogic prevMPOND; address _unused_1; IRewardDelegators public rewardDelegators; // new variables struct Lock { uint256 unlockBlock; uint256 iValue; } mapping(bytes32 => Lock) public locks; mapping(bytes32 => uint256) public lockWaitTime; bytes32 constant REDELEGATION_LOCK_SELECTOR = keccak256("REDELEGATION_LOCK"); uint256 public undelegationWaitTime; event StashCreated( address indexed creator, bytes32 stashId, uint256 stashIndex, bytes32[] tokens, uint256[] amounts ); event StashDelegated(bytes32 stashId, address delegatedCluster); event StashUndelegated(bytes32 stashId, address undelegatedCluster, uint256 undelegatesAt); event StashWithdrawn(bytes32 stashId, bytes32[] tokens, uint256[] amounts); event StashClosed(bytes32 stashId, address indexed staker); event AddedToStash(bytes32 stashId, address delegatedCluster, bytes32[] tokens, uint256[] amounts); event TokenAdded(bytes32 tokenId, address tokenAddress); event TokenRemoved(bytes32 tokenId); event TokenUpdated(bytes32 tokenId, address tokenAddress); event RedelegationRequested(bytes32 stashId, address currentCluster, address updatedCluster, uint256 redelegatesAt); event Redelegated(bytes32 stashId, address updatedCluster); event LockTimeUpdated(bytes32 selector, uint256 prevLockTime, uint256 updatedLockTime); event StashSplit( bytes32 _newStashId, bytes32 _stashId, uint256 _stashIndex, bytes32[] _splitTokens, uint256[] _splitAmounts ); event StashesMerged(bytes32 _stashId1, bytes32 _stashId2); event StashUndelegationCancelled(bytes32 _stashId); event UndelegationWaitTimeUpdated(uint256 undelegationWaitTime); event RedelegationCancelled(bytes32 indexed _stashId); function initialize( bytes32[] memory _tokenIds, address[] memory _tokenAddresses, address _MPONDTokenAddress, address _rewardDelegatorsAddress, address _owner, uint256 _undelegationWaitTime) initializer public { require( _tokenIds.length == _tokenAddresses.length ); for(uint256 i=0; i < _tokenIds.length; i++) { tokenAddresses[_tokenIds[i]] = Token(_tokenAddresses[i], true); emit TokenAdded(_tokenIds[i], _tokenAddresses[i]); } MPOND = MPondLogic(_MPONDTokenAddress); rewardDelegators = IRewardDelegators(_rewardDelegatorsAddress); undelegationWaitTime = _undelegationWaitTime; super.initialize(_owner); } function updateLockWaitTime(bytes32 _selector, uint256 _updatedWaitTime) external onlyOwner { emit LockTimeUpdated(_selector, lockWaitTime[_selector], _updatedWaitTime); lockWaitTime[_selector] = _updatedWaitTime; } function changeMPONDTokenAddress( address _MPONDTokenAddress ) external onlyOwner { prevMPOND = MPOND; MPOND = MPondLogic(_MPONDTokenAddress); emit TokenUpdated(keccak256("MPOND"), _MPONDTokenAddress); } function updateRewardDelegators( address _updatedRewardDelegator ) external onlyOwner { require( _updatedRewardDelegator != address(0) ); rewardDelegators = IRewardDelegators(_updatedRewardDelegator); } function updateUndelegationWaitTime( uint256 _undelegationWaitTime ) external onlyOwner { undelegationWaitTime = _undelegationWaitTime; emit UndelegationWaitTimeUpdated(_undelegationWaitTime); } function enableToken( bytes32 _tokenId, address _address ) external onlyOwner { require( !tokenAddresses[_tokenId].isActive ); require(_address != address(0)); tokenAddresses[_tokenId] = Token(_address, true); emit TokenAdded(_tokenId, _address); } function disableToken( bytes32 _tokenId ) external onlyOwner { require( tokenAddresses[_tokenId].isActive ); tokenAddresses[_tokenId].isActive = false; emit TokenRemoved(_tokenId); } function createStashAndDelegate( bytes32[] memory _tokens, uint256[] memory _amounts, address _delegatedCluster ) public { bytes32 stashId = createStash(_tokens, _amounts); delegateStash(stashId, _delegatedCluster); } function createStash( bytes32[] memory _tokens, uint256[] memory _amounts ) public returns(bytes32) { require( _tokens.length == _amounts.length, "CS1" ); require( _tokens.length != 0, "CS2" ); uint256 _stashIndex = stashIndex; bytes32 _stashId = keccak256(abi.encodePacked(_stashIndex)); for(uint256 _index=0; _index < _tokens.length; _index++) { bytes32 _tokenId = _tokens[_index]; uint256 _amount = _amounts[_index]; require( tokenAddresses[_tokenId].isActive, "CS3" ); require( stashes[_stashId].amount[_tokenId] == 0, "CS4" ); require( _amount != 0, "CS5" ); stashes[_stashId].amount[_tokenId] = _amount; _lockTokens(_tokenId, _amount, msg.sender); } stashes[_stashId].staker = msg.sender; emit StashCreated(msg.sender, _stashId, _stashIndex, _tokens, _amounts); stashIndex = _stashIndex + 1; // Can't overflow return _stashId; } function addToStash( bytes32 _stashId, bytes32[] calldata _tokens, uint256[] calldata _amounts ) external { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "AS1" ); require( _stash.undelegatesAt <= block.number, "AS2" ); require( _tokens.length == _amounts.length, "AS3" ); if( _stash.delegatedCluster != address(0) ) { rewardDelegators.delegate(msg.sender, _stash.delegatedCluster, _tokens, _amounts); } for(uint256 i = 0; i < _tokens.length; i++) { bytes32 _tokenId = _tokens[i]; require( tokenAddresses[_tokenId].isActive, "AS4" ); if(_amounts[i] != 0) { stashes[_stashId].amount[_tokenId] = stashes[_stashId].amount[_tokenId].add(_amounts[i]); _lockTokens(_tokenId, _amounts[i], msg.sender); } } emit AddedToStash(_stashId, _stash.delegatedCluster, _tokens, _amounts); } function delegateStash(bytes32 _stashId, address _delegatedCluster) public { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "DS1" ); require( _delegatedCluster != address(0), "DS2" ); require( _stash.delegatedCluster == address(0), "DS3" ); require( _stash.undelegatesAt <= block.number, "DS4" ); stashes[_stashId].delegatedCluster = _delegatedCluster; delete stashes[_stashId].undelegatesAt; bytes32[] memory _tokens = rewardDelegators.getFullTokenList(); uint256[] memory _amounts = new uint256[](_tokens.length); for(uint256 i = 0; i < _tokens.length; i++) { _amounts[i] = stashes[_stashId].amount[_tokens[i]]; } rewardDelegators.delegate(msg.sender, _delegatedCluster, _tokens, _amounts); emit StashDelegated(_stashId, _delegatedCluster); } function requestStashRedelegation(bytes32 _stashId, address _newCluster) public { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "RSR1" ); require( _stash.delegatedCluster != address(0), "RSR2" ); require( _newCluster != address(0), "RSR3" ); uint256 _redelegationBlock = _requestStashRedelegation(_stashId, _newCluster); emit RedelegationRequested(_stashId, _stash.delegatedCluster, _newCluster, _redelegationBlock); } function _requestStashRedelegation(bytes32 _stashId, address _newCluster) internal returns(uint256) { bytes32 _lockId = keccak256(abi.encodePacked(REDELEGATION_LOCK_SELECTOR, _stashId)); uint256 _unlockBlock = locks[_lockId].unlockBlock; require( _unlockBlock == 0, "IRSR1" ); uint256 _redelegationBlock = block.number.add(lockWaitTime[REDELEGATION_LOCK_SELECTOR]); locks[_lockId] = Lock(_redelegationBlock, uint256(_newCluster)); return _redelegationBlock; } function requestStashRedelegations(bytes32[] memory _stashIds, address[] memory _newClusters) public { require(_stashIds.length == _newClusters.length, "SM:RSRs - Invalid input data"); for(uint256 i=0; i < _stashIds.length; i++) { requestStashRedelegation(_stashIds[i], _newClusters[i]); } } function redelegateStash(bytes32 _stashId) public { Stash memory _stash = stashes[_stashId]; require( _stash.delegatedCluster != address(0), "RS1" ); bytes32 _lockId = keccak256(abi.encodePacked(REDELEGATION_LOCK_SELECTOR, _stashId)); uint256 _unlockBlock = locks[_lockId].unlockBlock; require( _unlockBlock != 0 && _unlockBlock <= block.number, "RS2" ); address _updatedCluster = address(locks[_lockId].iValue); _redelegateStash(_stashId, _stash.staker, _stash.delegatedCluster, _updatedCluster); delete locks[_lockId]; } function _redelegateStash( bytes32 _stashId, address _staker, address _delegatedCluster, address _updatedCluster ) internal { bytes32[] memory _tokens = rewardDelegators.getFullTokenList(); uint256[] memory _amounts = new uint256[](_tokens.length); for(uint256 i=0; i < _tokens.length; i++) { _amounts[i] = stashes[_stashId].amount[_tokens[i]]; } if(_delegatedCluster != address(0)) { rewardDelegators.undelegate(_staker, _delegatedCluster, _tokens, _amounts); } rewardDelegators.delegate(_staker, _updatedCluster, _tokens, _amounts); stashes[_stashId].delegatedCluster = _updatedCluster; emit Redelegated(_stashId, _updatedCluster); } function splitStash(bytes32 _stashId, bytes32[] calldata _tokens, uint256[] calldata _amounts) external { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "SS1" ); require( _tokens.length != 0, "SS2" ); require( _tokens.length == _amounts.length, "SS3" ); uint256 _stashIndex = stashIndex; bytes32 _newStashId = keccak256(abi.encodePacked(_stashIndex)); for(uint256 _index=0; _index < _tokens.length; _index++) { bytes32 _tokenId = _tokens[_index]; uint256 _amount = _amounts[_index]; require( stashes[_newStashId].amount[_tokenId] == 0, "SS4" ); require( _amount != 0, "SS5" ); stashes[_stashId].amount[_tokenId] = stashes[_stashId].amount[_tokenId].sub( _amount, "SS6" ); stashes[_newStashId].amount[_tokenId] = _amount; } stashes[_newStashId].staker = msg.sender; stashes[_newStashId].delegatedCluster = _stash.delegatedCluster; stashes[_newStashId].undelegatesAt = _stash.undelegatesAt; emit StashSplit(_newStashId, _stashId, _stashIndex, _tokens, _amounts); stashIndex = _stashIndex + 1; } function mergeStash(bytes32 _stashId1, bytes32 _stashId2) external { require(_stashId1 != _stashId2, "MS1"); Stash memory _stash1 = stashes[_stashId1]; Stash memory _stash2 = stashes[_stashId2]; require( _stash1.staker == msg.sender && _stash2.staker == msg.sender, "MS2" ); require( _stash1.delegatedCluster == _stash2.delegatedCluster, "MS3" ); require( (_stash1.undelegatesAt <= block.number) && (_stash2.undelegatesAt <= block.number), "MS4" ); bytes32 _lockId1 = keccak256(abi.encodePacked(REDELEGATION_LOCK_SELECTOR, _stashId1)); uint256 _unlockBlock1 = locks[_lockId1].unlockBlock; bytes32 _lockId2 = keccak256(abi.encodePacked(REDELEGATION_LOCK_SELECTOR, _stashId2)); uint256 _unlockBlock2 = locks[_lockId2].unlockBlock; require( _unlockBlock1 == 0 && _unlockBlock2 == 0, "MS5" ); bytes32[] memory _tokens = rewardDelegators.getFullTokenList(); for(uint256 i=0; i < _tokens.length; i++) { uint256 _amount = stashes[_stashId2].amount[_tokens[i]]; if(_amount == 0) { continue; } delete stashes[_stashId2].amount[_tokens[i]]; stashes[_stashId1].amount[_tokens[i]] = stashes[_stashId1].amount[_tokens[i]].add(_amount); } delete stashes[_stashId2]; emit StashesMerged(_stashId1, _stashId2); } function redelegateStashes(bytes32[] memory _stashIds) public { for(uint256 i=0; i < _stashIds.length; i++) { redelegateStash(_stashIds[i]); } } function cancelRedelegation(bytes32 _stashId) public { require( msg.sender == stashes[_stashId].staker, "CR1" ); require(_cancelRedelegation(_stashId), "CR2"); } function _cancelRedelegation(bytes32 _stashId) internal returns(bool) { bytes32 _lockId = keccak256(abi.encodePacked(REDELEGATION_LOCK_SELECTOR, _stashId)); if(locks[_lockId].unlockBlock != 0) { delete locks[_lockId]; emit RedelegationCancelled(_stashId); return true; } return false; } function undelegateStash(bytes32 _stashId) public { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "US1" ); require( _stash.delegatedCluster != address(0), "US2" ); uint256 _waitTime = undelegationWaitTime; uint256 _undelegationBlock = block.number.add(_waitTime); stashes[_stashId].undelegatesAt = _undelegationBlock; delete stashes[_stashId].delegatedCluster; _cancelRedelegation(_stashId); bytes32[] memory _tokens = rewardDelegators.getFullTokenList(); uint256[] memory _amounts = new uint256[](_tokens.length); for(uint256 i=0; i < _tokens.length; i++) { _amounts[i] = stashes[_stashId].amount[_tokens[i]]; } rewardDelegators.undelegate(msg.sender, _stash.delegatedCluster, _tokens, _amounts); emit StashUndelegated(_stashId, _stash.delegatedCluster, _undelegationBlock); } function undelegateStashes(bytes32[] memory _stashIds) public { for(uint256 i=0; i < _stashIds.length; i++) { undelegateStash(_stashIds[i]); } } function cancelUndelegation(bytes32 _stashId, address _delegatedCluster) public { address _staker = stashes[_stashId].staker; uint256 _undelegatesAt = stashes[_stashId].undelegatesAt; require( _staker == msg.sender, "CU1" ); require( _undelegatesAt > block.number, "CU2" ); require( _undelegatesAt < block.number .add(undelegationWaitTime) .sub(lockWaitTime[REDELEGATION_LOCK_SELECTOR]), "CU3" ); delete stashes[_stashId].undelegatesAt; emit StashUndelegationCancelled(_stashId); _redelegateStash(_stashId, _staker, address(0), _delegatedCluster); } function withdrawStash(bytes32 _stashId) external { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "WS1" ); require( _stash.delegatedCluster == address(0), "WS2" ); require( _stash.undelegatesAt <= block.number, "WS3" ); bytes32[] memory _tokens = rewardDelegators.getFullTokenList(); uint256[] memory _amounts = new uint256[](_tokens.length); for(uint256 i=0; i < _tokens.length; i++) { _amounts[i] = stashes[_stashId].amount[_tokens[i]]; if(_amounts[i] == 0) continue; delete stashes[_stashId].amount[_tokens[i]]; _unlockTokens(_tokens[i], _amounts[i], msg.sender); } // Other items already zeroed delete stashes[_stashId].staker; delete stashes[_stashId].undelegatesAt; emit StashWithdrawn(_stashId, _tokens, _amounts); emit StashClosed(_stashId, msg.sender); } function withdrawStash( bytes32 _stashId, bytes32[] calldata _tokens, uint256[] calldata _amounts ) external { Stash memory _stash = stashes[_stashId]; require( _stash.staker == msg.sender, "WSC1" ); require( _stash.delegatedCluster == address(0), "WSC2" ); require( _stash.undelegatesAt <= block.number, "WSC3" ); require( _tokens.length == _amounts.length, "WSC4" ); for(uint256 i=0; i < _tokens.length; i++) { uint256 _balance = stashes[_stashId].amount[_tokens[i]]; require( _balance >= _amounts[i], "WSC5" ); if(_balance == _amounts[i]) { delete stashes[_stashId].amount[_tokens[i]]; } else { stashes[_stashId].amount[_tokens[i]] = _balance.sub(_amounts[i]); } _unlockTokens(_tokens[i], _amounts[i], msg.sender); } emit StashWithdrawn(_stashId, _tokens, _amounts); } function _lockTokens(bytes32 _tokenId, uint256 _amount, address _delegator) internal { if(_amount == 0) { return; } address tokenAddress = tokenAddresses[_tokenId].addr; // pull tokens from mpond/pond contract // if mpond transfer the governance rights back require( ERC20(tokenAddress).transferFrom( _delegator, address(this), _amount ), "LT1" ); if (tokenAddress == address(MPOND)) { // send a request to delegate governance rights for the amount to delegator MPOND.delegate( _delegator, uint96(_amount) ); } } function _unlockTokens(bytes32 _tokenId, uint256 _amount, address _delegator) internal { if(_amount == 0) { return; } address tokenAddress = tokenAddresses[_tokenId].addr; if(tokenAddress == address(MPOND)) { // send a request to undelegate governacne rights for the amount to previous delegator MPOND.undelegate( _delegator, uint96(_amount) ); } else if(tokenAddress == address(prevMPOND)) { prevMPOND.undelegate( _delegator, uint96(_amount) ); } require( ERC20(tokenAddress).transfer( _delegator, _amount ), "UT1" ); } function getTokenAmountInStash(bytes32 _stashId, bytes32 _tokenId) external view returns(uint256) { return stashes[_stashId].amount[_tokenId]; } }
File 5 of 10: RewardDelegators
/** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * ////IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.17; interface IClusterRegistry { function locks(bytes32 _lockId) external returns(uint256, uint256); function lockWaitTime(bytes32 _selectorId) external returns(uint256); function updateLockWaitTime(bytes32 _selector, uint256 _updatedWaitTime) external; function register( bytes32 _networkId, uint256 _commission, address _rewardAddress, address _clientKey ) external returns(bool); function updateCluster( uint256 _commission, bytes32 _networkId, address _rewardAddress, address _clientKey ) external; function updateCommission(uint256 _commission) external; function switchNetwork(bytes32 _networkId) external; function updateRewardAddress(address _rewardAddress) external; function updateClientKey(address _clientKey) external; function unregister() external; function isClusterValid(address _cluster) external returns(bool); function getCommission(address _cluster) external returns(uint256); function getNetwork(address _cluster) external returns(bytes32); function getRewardAddress(address _cluster) external view returns(address); function getClientKey(address _cluster) external view returns(address); function getCluster(address _cluster) external; function getRewardInfo(address _cluster) external returns(uint256, address); } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.17; interface IClusterRewards { function clusterRewards(address _cluster) external returns(uint256); function rewardWeight(bytes32 _networkId) external returns(uint256); function totalRewardsPerEpoch() external returns(uint256); function feeder() external returns(address); function rewardDistributionWaitTime() external returns(uint256); function changeFeeder(address _newFeeder) external; function addNetwork(bytes32 _networkId, uint256 _rewardWeight) external; function removeNetwork(bytes32 _networkId) external; function changeNetworkReward(bytes32 _networkId, uint256 _updatedRewardWeight) external; function feed(bytes32 _networkId, address[] calldata _clusters, uint256[] calldata _payouts, uint256 _epoch) external; function getRewardPerEpoch(bytes32 _networkId) external view returns(uint256); function claimReward(address _cluster) external returns(uint256); function updateRewardDelegatorAddress(address _updatedRewardDelegator) external; function updatePONDAddress(address _updatedPOND) external; function changeRewardPerEpoch(uint256 _updatedRewardPerEpoch) external; function changePayoutDenomination(uint256 _updatedPayoutDenomination) external; function updateRewardDistributionWaitTime(uint256 _updatedRewardDistributionWaitTime) external; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.0; ////import "../../GSN/Context.sol"; ////import "./IERC20.sol"; ////import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity ^0.5.0; ////import "../GSN/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * > Note: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/RewardDelegators.sol */ pragma solidity >=0.4.21 <0.7.0; contract RewardDelegators is Initializable, Ownable { using SafeMath for uint256; struct Cluster { mapping(bytes32 => uint256) totalDelegations; mapping(address => mapping(bytes32 => uint256)) delegators; mapping(address => mapping(bytes32 => uint256)) rewardDebt; mapping(bytes32 => uint256) accRewardPerShare; } mapping(address => Cluster) clusters; uint256 __unused_2; address stakeAddress; uint256 public minMPONDStake; bytes32 public MPONDTokenId; mapping(bytes32 => uint256) rewardFactor; mapping(bytes32 => uint256) tokenIndex; mapping(bytes32 => bytes32) __unused_1; bytes32[] tokenList; IClusterRewards clusterRewards; IClusterRegistry clusterRegistry; ERC20 PONDToken; event AddReward(bytes32 tokenId, uint256 rewardFactor); event RemoveReward(bytes32 tokenId); event MPONDTokenIdUpdated(bytes32 MPONDTokenId); event RewardsUpdated(bytes32 tokenId, uint256 rewardFactor); event ClusterRewardDistributed(address cluster); event RewardsWithdrawn(address cluster, address delegator, bytes32[] tokenIds, uint256 rewards); event MinMPONDStakeUpdated(uint256 minMPONDStake); event StakeAddressUpdated(address _updatedStakeAddress); event ClusterRewardsAddressUpdated(address _updatedClusterRewards); event ClusterRegistryUpdated(address _updatedClusterRegistry); event PONDAddressUpdated(address _updatedPOND); modifier onlyStake() { require(msg.sender == stakeAddress, "RD:OS-only stake contract can invoke"); _; } function initialize( address _stakeAddress, address _clusterRewardsAddress, address _clusterRegistry, address _rewardDelegatorsAdmin, uint256 _minMPONDStake, bytes32 _MPONDTokenId, address _PONDAddress, bytes32[] memory _tokenIds, uint256[] memory _rewardFactors ) public initializer { require( _tokenIds.length == _rewardFactors.length, "RD:I-Each TokenId should have a corresponding Reward Factor and vice versa" ); stakeAddress = _stakeAddress; clusterRegistry = IClusterRegistry(_clusterRegistry); clusterRewards = IClusterRewards(_clusterRewardsAddress); PONDToken = ERC20(_PONDAddress); minMPONDStake = _minMPONDStake; emit MinMPONDStakeUpdated(_minMPONDStake); MPONDTokenId = _MPONDTokenId; emit MPONDTokenIdUpdated(_MPONDTokenId); for(uint256 i=0; i < _tokenIds.length; i++) { rewardFactor[_tokenIds[i]] = _rewardFactors[i]; tokenIndex[_tokenIds[i]] = tokenList.length; tokenList.push(_tokenIds[i]); emit AddReward(_tokenIds[i], _rewardFactors[i]); } super.initialize(_rewardDelegatorsAdmin); } function updateMPONDTokenId(bytes32 _updatedMPONDTokenId) external onlyOwner { MPONDTokenId = _updatedMPONDTokenId; emit MPONDTokenIdUpdated(_updatedMPONDTokenId); } function addRewardFactor(bytes32 _tokenId, uint256 _rewardFactor) external onlyOwner { require(rewardFactor[_tokenId] == 0, "RD:AR-Reward already exists"); require(_rewardFactor != 0, "RD:AR-Reward cant be 0"); rewardFactor[_tokenId] = _rewardFactor; tokenIndex[_tokenId] = tokenList.length; tokenList.push(_tokenId); emit AddReward(_tokenId, _rewardFactor); } function removeRewardFactor(bytes32 _tokenId) external onlyOwner { require(rewardFactor[_tokenId] != 0, "RD:RR-Reward doesnt exist"); bytes32 tokenToReplace = tokenList[tokenList.length - 1]; uint256 originalTokenIndex = tokenIndex[_tokenId]; tokenList[originalTokenIndex] = tokenToReplace; tokenIndex[tokenToReplace] = originalTokenIndex; tokenList.pop(); delete rewardFactor[_tokenId]; delete tokenIndex[_tokenId]; emit RemoveReward(_tokenId); } function updateRewardFactor(bytes32 _tokenId, uint256 _updatedRewardFactor) external onlyOwner { require(rewardFactor[_tokenId] != 0, "RD:UR-Cant update reward that doesnt exist"); require(_updatedRewardFactor != 0, "RD:UR-Reward cant be 0"); rewardFactor[_tokenId] = _updatedRewardFactor; emit RewardsUpdated(_tokenId, _updatedRewardFactor); } function _updateRewards(address _cluster) public { uint256 reward = clusterRewards.claimReward(_cluster); if(reward == 0) { return; } (uint256 _commission, address _rewardAddress) = clusterRegistry.getRewardInfo(_cluster); uint256 commissionReward = reward.mul(_commission).div(100); uint256 delegatorReward = reward.sub(commissionReward); bytes32[] memory tokens = tokenList; uint256[] memory delegations = new uint256[](tokens.length); uint256 delegatedTokens = 0; for(uint i=0; i < tokens.length; i++) { delegations[i] = clusters[_cluster].totalDelegations[tokens[i]]; if(delegations[i] != 0) { delegatedTokens++; } } for(uint i=0; i < tokens.length; i++) { // clusters[_cluster].accRewardPerShare[tokens[i]] = clusters[_cluster].accRewardPerShare[tokens[i]].add( // delegatorReward // .mul(rewardFactor[tokens[i]]) // .mul(10**30) // .div(weightedStake) // ); if(delegations[i] != 0) { clusters[_cluster].accRewardPerShare[tokens[i]] = clusters[_cluster].accRewardPerShare[tokens[i]].add( delegatorReward .mul(10**30) .div(delegatedTokens) .div(delegations[i]) ); } } if(commissionReward != 0) { transferRewards(_rewardAddress, commissionReward); } emit ClusterRewardDistributed(_cluster); } function delegate( address _delegator, address _cluster, bytes32[] memory _tokens, uint256[] memory _amounts ) public onlyStake { _updateTokens(_delegator, _cluster, _tokens, _amounts, true); } function _updateTokens( address _delegator, address _cluster, bytes32[] memory _tokens, uint256[] memory _amounts, bool _isDelegation ) internal returns(uint256 _aggregateReward) { _updateRewards(_cluster); for(uint256 i = 0; i < _tokens.length; i++) { bytes32 _tokenId = _tokens[i]; uint256 _amount = _amounts[i]; (uint256 _oldBalance, uint256 _newBalance) = _updateBalances( _cluster, _delegator, _tokenId, _amount, _isDelegation ); uint256 _reward = _updateDelegatorRewards( _cluster, _delegator, _tokenId, _oldBalance, _newBalance ); _aggregateReward = _aggregateReward.add(_reward); } if(_aggregateReward != 0) { transferRewards(_delegator, _aggregateReward); emit RewardsWithdrawn(_cluster, _delegator, _tokens, _aggregateReward); } } function _updateBalances( address _cluster, address _delegator, bytes32 _tokenId, uint256 _amount, bool _isDelegation ) internal returns(uint256 _oldBalance, uint256 _newBalance) { _oldBalance = clusters[_cluster].delegators[_delegator][_tokenId]; // short circuit if(_amount == 0) { _newBalance = _oldBalance; return (_oldBalance, _newBalance); } // update balances if(_isDelegation) { _newBalance = _oldBalance.add(_amount); clusters[_cluster].totalDelegations[_tokenId] = clusters[_cluster].totalDelegations[_tokenId] .add(_amount); } else { _newBalance = _oldBalance.sub(_amount); clusters[_cluster].totalDelegations[_tokenId] = clusters[_cluster].totalDelegations[_tokenId] .sub(_amount); } clusters[_cluster].delegators[_delegator][_tokenId] = _newBalance; } function _updateDelegatorRewards( address _cluster, address _delegator, bytes32 _tokenId, uint256 _oldBalance, uint256 _newBalance ) internal returns(uint256 _reward) { uint256 _accRewardPerShare = clusters[_cluster].accRewardPerShare[_tokenId]; uint256 _rewardDebt = clusters[_cluster].rewardDebt[_delegator][_tokenId]; // pending rewards uint256 _tokenPendingRewards = _accRewardPerShare.mul(_oldBalance).div(10**30); // calculating pending rewards for the delegator if any _reward = _tokenPendingRewards.sub(_rewardDebt); // short circuit if(_oldBalance == _newBalance && _reward == 0) { return _reward; } // update the debt for next reward calculation clusters[_cluster].rewardDebt[_delegator][_tokenId] = _accRewardPerShare.mul(_newBalance).div(10**30); } function undelegate( address _delegator, address _cluster, bytes32[] memory _tokens, uint256[] memory _amounts ) public onlyStake { _updateTokens(_delegator, _cluster, _tokens, _amounts, false); } function withdrawRewards(address _delegator, address _cluster) public returns(uint256) { return _updateTokens(_delegator, _cluster, tokenList, new uint256[](tokenList.length), true); } function withdrawRewards(address _delegator, address[] calldata _clusters) external { for(uint256 i=0; i < _clusters.length; i++) { withdrawRewards(_delegator, _clusters[i]); } } function transferRewards(address _to, uint256 _amount) internal { PONDToken.transfer(_to, _amount); } function isClusterActive(address _cluster) external returns(bool) { if( clusterRegistry.isClusterValid(_cluster) && clusters[_cluster].totalDelegations[MPONDTokenId] > minMPONDStake ) { return true; } return false; } function getClusterDelegation(address _cluster, bytes32 _tokenId) external view returns(uint256) { return clusters[_cluster].totalDelegations[_tokenId]; } function getDelegation(address _cluster, address _delegator, bytes32 _tokenId) external view returns(uint256) { return clusters[_cluster].delegators[_delegator][_tokenId]; } function updateMinMPONDStake(uint256 _minMPONDStake) external onlyOwner { minMPONDStake = _minMPONDStake; emit MinMPONDStakeUpdated(_minMPONDStake); } function updateStakeAddress(address _updatedStakeAddress) external onlyOwner { require( _updatedStakeAddress != address(0), "RD:USA-Stake contract address cant be 0" ); stakeAddress = _updatedStakeAddress; emit StakeAddressUpdated(_updatedStakeAddress); } function updateClusterRewards( address _updatedClusterRewards ) external onlyOwner { require( _updatedClusterRewards != address(0), "RD:UCR-ClusterRewards address cant be 0" ); clusterRewards = IClusterRewards(_updatedClusterRewards); emit ClusterRewardsAddressUpdated(_updatedClusterRewards); } function updateClusterRegistry( address _updatedClusterRegistry ) external onlyOwner { require( _updatedClusterRegistry != address(0), "RD:UCR-Cluster Registry address cant be 0" ); clusterRegistry = IClusterRegistry(_updatedClusterRegistry); emit ClusterRegistryUpdated(_updatedClusterRegistry); } function updatePONDAddress(address _updatedPOND) external onlyOwner { require( _updatedPOND != address(0), "RD:UPA-Updated POND token address cant be 0" ); PONDToken = ERC20(_updatedPOND); emit PONDAddressUpdated(_updatedPOND); } function getFullTokenList() external view returns (bytes32[] memory) { return tokenList; } function getAccRewardPerShare(address _cluster, bytes32 _tokenId) external view returns(uint256) { return clusters[_cluster].accRewardPerShare[_tokenId]; } }
File 6 of 10: ClusterRewardsProxy
pragma solidity >=0.4.21 <0.7.0; /// @title Contract to reward overlapping stakes /// @author Marlin /// @notice Use this contract only for testing /// @dev Contract may or may not change in future (depending upon the new slots in proxy-store) contract ClusterRewardsProxy { bytes32 internal constant IMPLEMENTATION_SLOT = bytes32( uint256(keccak256("eip1967.proxy.implementation")) - 1 ); bytes32 internal constant PROXY_ADMIN_SLOT = bytes32( uint256(keccak256("eip1967.proxy.admin")) - 1 ); constructor(address contractLogic, address proxyAdmin) public { // save the code address bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, contractLogic) } // save the proxy admin slot = PROXY_ADMIN_SLOT; address sender = proxyAdmin; assembly { sstore(slot, sender) } } function updateAdmin(address _newAdmin) public { require( msg.sender == getAdmin(), "Only the current admin should be able to new admin" ); bytes32 slot = PROXY_ADMIN_SLOT; assembly { sstore(slot, _newAdmin) } } /// @author Marlin /// @dev Only admin can update the contract /// @param _newLogic address is the address of the contract that has to updated to function updateLogic(address _newLogic) public { require( msg.sender == getAdmin(), "Only Admin should be able to update the contracts" ); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, _newLogic) } } /// @author Marlin /// @dev use assembly as contract store slot is manually decided function getAdmin() internal view returns (address result) { bytes32 slot = PROXY_ADMIN_SLOT; assembly { result := sload(slot) } } /// @author Marlin /// @dev add functionality to forward the balance as well. function() external payable { bytes32 slot = IMPLEMENTATION_SLOT; assembly { let contractLogic := sload(slot) calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } }
File 7 of 10: ClusterRewards
/** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * ////IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity ^0.5.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * > Note: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRewards.sol */ pragma solidity >=0.4.21 <0.7.0; contract ClusterRewards is Initializable, Ownable { using SafeMath for uint256; mapping(address => uint256) public clusterRewards; mapping(bytes32 => uint256) public rewardWeight; uint256 totalWeight; uint256 public totalRewardsPerEpoch; uint256 payoutDenomination; address rewardDelegatorsAddress; ERC20 POND; address public feeder; mapping(uint256 => uint256) rewardDistributedPerEpoch; uint256 latestNewEpochRewardAt; uint256 public rewardDistributionWaitTime; event NetworkAdded(bytes32 networkId, uint256 rewardPerEpoch); event NetworkRemoved(bytes32 networkId); event NetworkRewardUpdated(bytes32 networkId, uint256 updatedRewardPerEpoch); event ClusterRewarded(bytes32 networkId); event FeederChanged(address _newFeeder); event RewardDelegatorAddressUpdated(address _updatedRewardDelegator); event PONDAddressUpdated(address _updatedPOND); event RewardPerEpochChanged(uint256 _updatedRewardPerEpoch); event PayoutDenominationChanged(uint256 _updatedPayoutDenomination); event RewardDistributionWaitTimeUpdated(uint256 _updatedRewardDistributionWaitTime); modifier onlyRewardDelegatorsContract() { require(msg.sender == rewardDelegatorsAddress, "Sender not Reward Delegators contract"); _; } modifier onlyFeeder() { require(msg.sender == feeder, "Sender not feeder"); _; } function initialize( address _owner, address _rewardDelegatorsAddress, bytes32[] memory _networkIds, uint256[] memory _rewardWeight, uint256 _totalRewardsPerEpoch, address _PONDAddress, uint256 _payoutDenomination, address _feeder, uint256 _rewardDistributionWaitTime) public initializer { require( _networkIds.length == _rewardWeight.length, "CRW:I-Each NetworkId need a corresponding RewardPerEpoch and vice versa" ); super.initialize(_owner); uint256 weight = 0; rewardDelegatorsAddress = _rewardDelegatorsAddress; for(uint256 i=0; i < _networkIds.length; i++) { rewardWeight[_networkIds[i]] = _rewardWeight[i]; weight = weight.add(_rewardWeight[i]); emit NetworkAdded(_networkIds[i], _rewardWeight[i]); } totalWeight = weight; totalRewardsPerEpoch = _totalRewardsPerEpoch; POND = ERC20(_PONDAddress); payoutDenomination = _payoutDenomination; feeder = _feeder; rewardDistributionWaitTime = _rewardDistributionWaitTime; } function changeFeeder(address _newFeeder) external onlyOwner { feeder = _newFeeder; emit FeederChanged(_newFeeder); } function addNetwork(bytes32 _networkId, uint256 _rewardWeight) external onlyOwner { require(rewardWeight[_networkId] == 0, "CRW:AN-Network already exists"); require(_rewardWeight != 0, "CRW:AN-Reward cant be 0"); rewardWeight[_networkId] = _rewardWeight; totalWeight = totalWeight.add(_rewardWeight); emit NetworkAdded(_networkId, _rewardWeight); } function removeNetwork(bytes32 _networkId) external onlyOwner { uint256 networkWeight = rewardWeight[_networkId]; require( networkWeight != 0, "CRW:RN-Network doesnt exist"); delete rewardWeight[_networkId]; totalWeight = totalWeight.sub(networkWeight); emit NetworkRemoved(_networkId); } function changeNetworkReward(bytes32 _networkId, uint256 _updatedRewardWeight) external onlyOwner { uint256 networkWeight = rewardWeight[_networkId]; require( networkWeight != 0, "CRW:CNR-Network doesnt exist"); rewardWeight[_networkId] = _updatedRewardWeight; totalWeight = totalWeight.sub(networkWeight).add(_updatedRewardWeight); emit NetworkRewardUpdated(_networkId, _updatedRewardWeight); } function feed( bytes32 _networkId, address[] calldata _clusters, uint256[] calldata _payouts, uint256 _epoch ) external onlyFeeder { uint256 rewardDistributed = rewardDistributedPerEpoch[_epoch]; if(rewardDistributed == 0) { require( block.timestamp > latestNewEpochRewardAt.add(rewardDistributionWaitTime), "CRW:F-Cant distribute reward for new epoch within such short interval" ); latestNewEpochRewardAt = block.timestamp; } uint256 totalNetworkWeight = totalWeight; uint256 currentTotalRewardsPerEpoch = totalRewardsPerEpoch; uint256 currentPayoutDenomination = payoutDenomination; uint256 networkRewardWeight = rewardWeight[_networkId]; for(uint256 i=0; i < _clusters.length; i++) { uint256 clusterReward = currentTotalRewardsPerEpoch .mul(networkRewardWeight) .mul(_payouts[i]) .div(totalNetworkWeight) .div(currentPayoutDenomination); rewardDistributed = rewardDistributed.add(clusterReward); clusterRewards[_clusters[i]] = clusterRewards[_clusters[i]].add(clusterReward); } require( rewardDistributed <= totalRewardsPerEpoch, "CRW:F-Reward Distributed cant be more than totalRewardPerEpoch" ); rewardDistributedPerEpoch[_epoch] = rewardDistributed; emit ClusterRewarded(_networkId); } function getRewardPerEpoch(bytes32 _networkId) external view returns(uint256) { return totalRewardsPerEpoch.mul(rewardWeight[_networkId]).div(totalWeight); } // only cluster registry is necessary because the rewards // should be updated in the cluster registry against the cluster function claimReward(address _cluster) external onlyRewardDelegatorsContract returns(uint256) { uint256 pendingRewards = clusterRewards[_cluster]; if(pendingRewards > 1) { uint256 rewardsToTransfer = pendingRewards.sub(1); clusterRewards[_cluster] = 1; return rewardsToTransfer; } return 0; } function transferRewardsToRewardDelegators() external onlyOwner returns(uint256) { POND.transfer(rewardDelegatorsAddress, POND.balanceOf(address(this))); } function updateRewardDelegatorAddress(address _updatedRewardDelegator) external onlyOwner { require( _updatedRewardDelegator != address(0), "CRW:URDA-Updated Reward delegator address cant be 0" ); rewardDelegatorsAddress = _updatedRewardDelegator; emit RewardDelegatorAddressUpdated(_updatedRewardDelegator); } function updatePONDAddress(address _updatedPOND) external onlyOwner { require( _updatedPOND != address(0), "CRW:UPA-POND token address cant be 0" ); POND = ERC20(_updatedPOND); emit PONDAddressUpdated(_updatedPOND); } function changeRewardPerEpoch(uint256 _updatedRewardPerEpoch) external onlyOwner { totalRewardsPerEpoch = _updatedRewardPerEpoch; emit RewardPerEpochChanged(_updatedRewardPerEpoch); } function changePayoutDenomination(uint256 _updatedPayoutDenomination) external onlyOwner { payoutDenomination = _updatedPayoutDenomination; emit PayoutDenominationChanged(_updatedPayoutDenomination); } function updateRewardDistributionWaitTime(uint256 _updatedRewardDistributionWaitTime) external onlyOwner { rewardDistributionWaitTime = _updatedRewardDistributionWaitTime; emit RewardDistributionWaitTimeUpdated(_updatedRewardDistributionWaitTime); } }
File 8 of 10: ClusterRegistryProxy
pragma solidity >=0.4.21 <0.7.0; /// @title Contract to reward overlapping stakes /// @author Marlin /// @notice Use this contract only for testing /// @dev Contract may or may not change in future (depending upon the new slots in proxy-store) contract ClusterRegistryProxy { bytes32 internal constant IMPLEMENTATION_SLOT = bytes32( uint256(keccak256("eip1967.proxy.implementation")) - 1 ); bytes32 internal constant PROXY_ADMIN_SLOT = bytes32( uint256(keccak256("eip1967.proxy.admin")) - 1 ); constructor(address contractLogic, address proxyAdmin) public { // save the code address bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, contractLogic) } // save the proxy admin slot = PROXY_ADMIN_SLOT; address sender = proxyAdmin; assembly { sstore(slot, sender) } } function updateAdmin(address _newAdmin) public { require( msg.sender == getAdmin(), "Only the current admin should be able to new admin" ); bytes32 slot = PROXY_ADMIN_SLOT; assembly { sstore(slot, _newAdmin) } } /// @author Marlin /// @dev Only admin can update the contract /// @param _newLogic address is the address of the contract that has to updated to function updateLogic(address _newLogic) public { require( msg.sender == getAdmin(), "Only Admin should be able to update the contracts" ); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, _newLogic) } } /// @author Marlin /// @dev use assembly as contract store slot is manually decided function getAdmin() internal view returns (address result) { bytes32 slot = PROXY_ADMIN_SLOT; assembly { result := sload(slot) } } /// @author Marlin /// @dev add functionality to forward the balance as well. function() external payable { bytes32 slot = IMPLEMENTATION_SLOT; assembly { let contractLogic := sload(slot) calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } }
File 9 of 10: ClusterRegistry
/** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * ////IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity ^0.5.0; ////import "@openzeppelin/upgrades/contracts/Initializable.sol"; ////import "../../GSN/Context.sol"; ////import "./IERC20.sol"; ////import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity ^0.5.0; ////import "@openzeppelin/upgrades/contracts/Initializable.sol"; ////import "../GSN/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * > Note: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; } /** * SourceUnit: /Users/prateekyammanuru/work/marlin/contracts_github/Contracts/contracts/Stake/ClusterRegistry.sol */ pragma solidity >=0.4.21 <0.7.0; contract ClusterRegistry is Initializable, Ownable { using SafeMath for uint256; uint256 constant UINT256_MAX = ~uint256(0); struct Cluster { uint256 commission; address rewardAddress; address clientKey; bytes32 networkId; // keccak256("ETH") // token ticker for anyother chain in place of ETH Status status; } struct Lock { uint256 unlockBlock; uint256 iValue; } mapping(address => Cluster) clusters; mapping(bytes32 => Lock) public locks; mapping(bytes32 => uint256) public lockWaitTime; bytes32 constant COMMISSION_LOCK_SELECTOR = keccak256("COMMISSION_LOCK"); bytes32 constant SWITCH_NETWORK_LOCK_SELECTOR = keccak256("SWITCH_NETWORK_LOCK"); bytes32 constant UNREGISTER_LOCK_SELECTOR = keccak256("UNREGISTER_LOCK"); enum Status{NOT_REGISTERED, REGISTERED} mapping(address => address) public clientKeys; event ClusterRegistered( address cluster, bytes32 networkId, uint256 commission, address rewardAddress, address clientKey ); event CommissionUpdateRequested(address cluster, uint256 commissionAfterUpdate, uint256 effectiveBlock); event CommissionUpdated(address cluster, uint256 updatedCommission, uint256 updatedAt); event RewardAddressUpdated(address cluster, address updatedRewardAddress); event NetworkSwitchRequested(address cluster, bytes32 networkId, uint256 effectiveBlock); event NetworkSwitched(address cluster, bytes32 networkId, uint256 updatedAt); event ClientKeyUpdated(address cluster, address clientKey); event ClusterUnregisterRequested(address cluster, uint256 effectiveBlock); event ClusterUnregistered(address cluster, uint256 updatedAt); event LockTimeUpdated(bytes32 selector, uint256 prevLockTime, uint256 updatedLockTime); function initialize(bytes32[] memory _selectors, uint256[] memory _lockWaitTimes, address _owner) public initializer { require( _selectors.length == _lockWaitTimes.length, "CR:I-Invalid params" ); for(uint256 i=0; i < _selectors.length; i++) { lockWaitTime[_selectors[i]] = _lockWaitTimes[i]; emit LockTimeUpdated(_selectors[i], 0, _lockWaitTimes[i]); } super.initialize(_owner); } function updateLockWaitTime(bytes32 _selector, uint256 _updatedWaitTime) external onlyOwner { emit LockTimeUpdated(_selector, lockWaitTime[_selector], _updatedWaitTime); lockWaitTime[_selector] = _updatedWaitTime; } function register( bytes32 _networkId, uint256 _commission, address _rewardAddress, address _clientKey ) external returns(bool) { // This happens only when the data of the cluster is registered or it wasn't registered before require( !isClusterValid(msg.sender), "CR:R-Cluster is already registered" ); require(_commission <= 100, "CR:R-Commission more than 100%"); require(clientKeys[_clientKey] == address(0), "CR:R - Client key is already used"); clusters[msg.sender].commission = _commission; clusters[msg.sender].rewardAddress = _rewardAddress; clusters[msg.sender].clientKey = _clientKey; clusters[msg.sender].networkId = _networkId; clusters[msg.sender].status = Status.REGISTERED; clientKeys[_clientKey] = msg.sender; emit ClusterRegistered(msg.sender, _networkId, _commission, _rewardAddress, _clientKey); } function updateCluster(uint256 _commission, bytes32 _networkId, address _rewardAddress, address _clientKey) public { if(_networkId != bytes32(0)) { switchNetwork(_networkId); } if(_rewardAddress != address(0)) { updateRewardAddress(_rewardAddress); } if(_clientKey != address(0)) { updateClientKey(_clientKey); } if(_commission != UINT256_MAX) { updateCommission(_commission); } } function updateCommission(uint256 _commission) public { require( isClusterValid(msg.sender), "CR:UCM-Cluster not registered" ); require(_commission <= 100, "CR:UCM-Commission more than 100%"); bytes32 lockId = keccak256(abi.encodePacked(COMMISSION_LOCK_SELECTOR, msg.sender)); uint256 unlockBlock = locks[lockId].unlockBlock; require( unlockBlock < block.number, "CR:UCM-Commission update in progress" ); if(unlockBlock != 0) { uint256 currentCommission = locks[lockId].iValue; clusters[msg.sender].commission = currentCommission; emit CommissionUpdated(msg.sender, currentCommission, unlockBlock); } uint256 updatedUnlockBlock = block.number.add(lockWaitTime[COMMISSION_LOCK_SELECTOR]); locks[lockId] = Lock(updatedUnlockBlock, _commission); emit CommissionUpdateRequested(msg.sender, _commission, updatedUnlockBlock); } function switchNetwork(bytes32 _networkId) public { require( isClusterValid(msg.sender), "CR:SN-Cluster not registered" ); bytes32 lockId = keccak256(abi.encodePacked(SWITCH_NETWORK_LOCK_SELECTOR, msg.sender)); uint256 unlockBlock = locks[lockId].unlockBlock; require( unlockBlock < block.number, "CR:SN-Network switch in progress" ); if(unlockBlock != 0) { bytes32 currentNetwork = bytes32(locks[lockId].iValue); clusters[msg.sender].networkId = currentNetwork; emit NetworkSwitched(msg.sender, currentNetwork, unlockBlock); } uint256 updatedUnlockBlock = block.number.add(lockWaitTime[SWITCH_NETWORK_LOCK_SELECTOR]); locks[lockId] = Lock(updatedUnlockBlock, uint256(_networkId)); emit NetworkSwitchRequested(msg.sender, _networkId, updatedUnlockBlock); } function updateRewardAddress(address _rewardAddress) public { require( isClusterValid(msg.sender), "CR:URA-Cluster not registered" ); clusters[msg.sender].rewardAddress = _rewardAddress; emit RewardAddressUpdated(msg.sender, _rewardAddress); } function updateClientKey(address _clientKey) public { // TODO: Add delay to client key updates as well require( isClusterValid(msg.sender), "CR:UCK-Cluster not registered" ); require(clientKeys[_clientKey] == address(0), "CR:UCK - Client key is already used"); delete clientKeys[clusters[msg.sender].clientKey]; clusters[msg.sender].clientKey = _clientKey; clientKeys[_clientKey] = msg.sender; emit ClientKeyUpdated(msg.sender, _clientKey); } function unregister() external { require( clusters[msg.sender].status != Status.NOT_REGISTERED, "CR:UR-Cluster not registered" ); bytes32 lockId = keccak256(abi.encodePacked(UNREGISTER_LOCK_SELECTOR, msg.sender)); uint256 unlockBlock = locks[lockId].unlockBlock; require( unlockBlock < block.number, "CR:UR-Unregistration already in progress" ); if(unlockBlock != 0) { clusters[msg.sender].status = Status.NOT_REGISTERED; emit ClusterUnregistered(msg.sender, unlockBlock); delete clientKeys[clusters[msg.sender].clientKey]; delete locks[lockId]; delete locks[keccak256(abi.encodePacked(COMMISSION_LOCK_SELECTOR, msg.sender))]; delete locks[keccak256(abi.encodePacked(SWITCH_NETWORK_LOCK_SELECTOR, msg.sender))]; return; } uint256 updatedUnlockBlock = block.number.add(lockWaitTime[UNREGISTER_LOCK_SELECTOR]); locks[lockId] = Lock(updatedUnlockBlock, 0); emit ClusterUnregisterRequested(msg.sender, updatedUnlockBlock); } function isClusterValid(address _cluster) public returns(bool) { bytes32 lockId = keccak256(abi.encodePacked(UNREGISTER_LOCK_SELECTOR, _cluster)); uint256 unlockBlock = locks[lockId].unlockBlock; if(unlockBlock != 0 && unlockBlock < block.number) { clusters[_cluster].status = Status.NOT_REGISTERED; delete clientKeys[clusters[_cluster].clientKey]; emit ClusterUnregistered(_cluster, unlockBlock); delete locks[lockId]; delete locks[keccak256(abi.encodePacked(COMMISSION_LOCK_SELECTOR, msg.sender))]; delete locks[keccak256(abi.encodePacked(SWITCH_NETWORK_LOCK_SELECTOR, msg.sender))]; return false; } return (clusters[_cluster].status != Status.NOT_REGISTERED); // returns true if the status is registered } function getCommission(address _cluster) public returns(uint256) { bytes32 lockId = keccak256(abi.encodePacked(COMMISSION_LOCK_SELECTOR, _cluster)); uint256 unlockBlock = locks[lockId].unlockBlock; if(unlockBlock != 0 && unlockBlock < block.number) { uint256 currentCommission = locks[lockId].iValue; clusters[_cluster].commission = currentCommission; emit CommissionUpdated(_cluster, currentCommission, unlockBlock); delete locks[lockId]; return currentCommission; } return clusters[_cluster].commission; } function getNetwork(address _cluster) public returns(bytes32) { bytes32 lockId = keccak256(abi.encodePacked(SWITCH_NETWORK_LOCK_SELECTOR, _cluster)); uint256 unlockBlock = locks[lockId].unlockBlock; if(unlockBlock != 0 && unlockBlock < block.number) { bytes32 currentNetwork = bytes32(locks[lockId].iValue); clusters[msg.sender].networkId = currentNetwork; emit NetworkSwitched(msg.sender, currentNetwork, unlockBlock); delete locks[lockId]; return currentNetwork; } return clusters[_cluster].networkId; } function getRewardAddress(address _cluster) external view returns(address) { return clusters[_cluster].rewardAddress; } function getClientKey(address _cluster) external view returns(address) { return clusters[_cluster].clientKey; } function getCluster(address _cluster) external returns( uint256 commission, address rewardAddress, address clientKey, bytes32 networkId, bool isValidCluster ) { return ( getCommission(_cluster), clusters[_cluster].rewardAddress, clusters[_cluster].clientKey, getNetwork(_cluster), isClusterValid(_cluster) ); } function getRewardInfo(address _cluster) external returns(uint256, address) { return (getCommission(_cluster), clusters[_cluster].rewardAddress); } function addClientKeys(address[] calldata _clusters) external onlyOwner { for(uint256 i=0; i < _clusters.length; i++) { address _clientKey = clusters[_clusters[i]].clientKey; require(_clientKey != address(0), "CR:ACK - Cluster has invalid client key"); clientKeys[_clientKey] = _clusters[i]; } } }
File 10 of 10: TokenLogic
// File: @openzeppelin/upgrades/contracts/Initializable.sol pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they not should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, with should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see `ERC20Detailed`. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through `transferFrom`. This is * zero by default. * * This value changes when `approve` or `transferFrom` are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * > Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an `Approval` event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to `approve`. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol pragma solidity ^0.5.0; /** * @dev Implementation of the `IERC20` interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using `_mint`. * For a generic mechanism see `ERC20Mintable`. * * *For a detailed writeup see our guide [How to implement supply * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).* * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an `Approval` event is emitted on calls to `transferFrom`. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard `decreaseAllowance` and `increaseAllowance` * functions have been added to mitigate the well-known issues around setting * allowances. See `IERC20.approve`. */ contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See `IERC20.totalSupply`. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See `IERC20.balanceOf`. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See `IERC20.transfer`. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 value) public returns (bool) { _transfer(_msgSender(), to, value); return true; } /** * @dev See `IERC20.allowance`. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See `IERC20.approve`. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public returns (bool) { _approve(_msgSender(), spender, value); return true; } /** * @dev See `IERC20.transferFrom`. * * Emits an `Approval` event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of `ERC20`; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `value`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _transfer(from, to, value); _approve(from, _msgSender(), _allowances[from][_msgSender()].sub(value)); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in `IERC20.approve`. * * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in `IERC20.approve`. * * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue)); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to `transfer`, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a `Transfer` event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a `Transfer` event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destoys `amount` tokens from `account`, reducing the * total supply. * * Emits a `Transfer` event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 value) internal { require(account != address(0), "ERC20: burn from the zero address"); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an `Approval` event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 value) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = value; emit Approval(owner, spender, value); } /** * @dev Destoys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See `_burn` and `_approve`. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount)); } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol pragma solidity ^0.5.0; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is Initializable, IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ function initialize(string memory name, string memory symbol, uint8 decimals) public initializer { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * > Note that this information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * `IERC20.balanceOf` and `IERC20.transfer`. */ function decimals() public view returns (uint8) { return _decimals; } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/access/Roles.sol pragma solidity ^0.5.0; /** * @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(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); 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), "Roles: account is the zero address"); return role.bearer[account]; } } // File: @openzeppelin/contracts-ethereum-package/contracts/access/roles/MinterRole.sol pragma solidity ^0.5.0; contract MinterRole is Initializable, Context { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; function initialize(address sender) public initializer { if (!isMinter(sender)) { _addMinter(sender); } } modifier onlyMinter() { require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(_msgSender()); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Mintable.sol pragma solidity ^0.5.0; /** * @dev Extension of `ERC20` that adds a set of accounts with the `MinterRole`, * which have permission to mint (create) new tokens as they see fit. * * At construction, the deployer of the contract is the only minter. */ contract ERC20Mintable is Initializable, ERC20, MinterRole { function initialize(address sender) public initializer { MinterRole.initialize(sender); } /** * @dev See `ERC20._mint`. * * Requirements: * * - the caller must have the `MinterRole`. */ function mint(address account, uint256 amount) public onlyMinter returns (bool) { _mint(account, amount); return true; } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Capped.sol pragma solidity ^0.5.0; /** * @dev Extension of `ERC20Mintable` that adds a cap to the supply of tokens. */ contract ERC20Capped is Initializable, ERC20Mintable { uint256 private _cap; /** * @dev Sets the value of the `cap`. This value is immutable, it can only be * set once during construction. */ function initialize(uint256 cap, address sender) public initializer { ERC20Mintable.initialize(sender); require(cap > 0, "ERC20Capped: cap is 0"); _cap = cap; } /** * @dev Returns the cap on the token's total supply. */ function cap() public view returns (uint256) { return _cap; } /** * @dev See `ERC20Mintable.mint`. * * Requirements: * * - `value` must not cause the total supply to go over the cap. */ function _mint(address account, uint256 value) internal { require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded"); super._mint(account, value); } uint256[50] private ______gap; } // File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Burnable.sol pragma solidity ^0.5.0; /** * @dev Extension of `ERC20` that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ contract ERC20Burnable is Initializable, Context, ERC20 { /** * @dev Destoys `amount` tokens from the caller. * * See `ERC20._burn`. */ function burn(uint256 amount) public { _burn(_msgSender(), amount); } /** * @dev See `ERC20._burnFrom`. */ function burnFrom(address account, uint256 amount) public { _burnFrom(account, amount); } uint256[50] private ______gap; } // File: contracts/Token/TokenLogic.sol pragma solidity 0.5.17; // import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Mintable.sol"; contract TokenLogic is Initializable, ERC20, ERC20Detailed, // ERC20Mintable, ERC20Capped, ERC20Burnable { function initialize( string memory _name, string memory _symbol, uint8 _decimal, address _bridge ) public initializer { ERC20Detailed.initialize(_name, _symbol, _decimal); // ERC20Mintable.initialize(msg.sender); ERC20Capped.initialize(10000000000e18, msg.sender); mint(_bridge, 1000000000e18); } }