diff --git a/contracts/deploy/010_upgrade_single_asset_staking.js b/contracts/deploy/010_upgrade_single_asset_staking.js index 31d3e41a97..fe7bf33ff1 100644 --- a/contracts/deploy/010_upgrade_single_asset_staking.js +++ b/contracts/deploy/010_upgrade_single_asset_staking.js @@ -10,6 +10,7 @@ const { log, deployWithConfirmation, executeProposal, + sendProposal, } = require("../utils/deploy"); const { proposeArgs } = require("../utils/governor"); const { getTxOpts } = require("../utils/tx"); diff --git a/contracts/deployments/mainnet/.migrations.json b/contracts/deployments/mainnet/.migrations.json index ef3fdaff25..02cc43ad8d 100644 --- a/contracts/deployments/mainnet/.migrations.json +++ b/contracts/deployments/mainnet/.migrations.json @@ -5,5 +5,6 @@ "004_single_asset_staking": 1608192583, "007_upgrade_single_asset_staking": 1608527258, "008_ousd_reset": 1609285987, - "009_ousd_fix": 1609736357 + "009_ousd_fix": 1609736357, + "010_upgrade_single_asset_staking": 1609971639 } \ No newline at end of file diff --git a/contracts/deployments/mainnet/SingleAssetStaking.json b/contracts/deployments/mainnet/SingleAssetStaking.json index bcb267264a..2c78723170 100644 --- a/contracts/deployments/mainnet/SingleAssetStaking.json +++ b/contracts/deployments/mainnet/SingleAssetStaking.json @@ -1,5 +1,5 @@ { - "address": "0xF6c1a36a200c9aCc5046A86037Ffbe4e0eCb2d6a", + "address": "0x0Ed143d1D6d98f10db7151b66D76aA3956072b5a", "abi": [ { "constant": true, @@ -611,6 +611,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rate", + "type": "uint256" } ], "name": "Staked", @@ -630,6 +642,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" } ], "name": "Withdrawn", @@ -756,42 +774,42 @@ "type": "event" } ], - "transactionHash": "0xdfb3c52b30803839d449fa83c5fcfb24eb524d18c870e03ccca3b8d59161c31c", + "transactionHash": "0x9a998931bf39359cbfc6c186f28b3741e10102738241891a53fb005f3e109a5e", "receipt": { "to": null, "from": "0x71F78361537A6f7B6818e7A760c8bC0146D93f50", - "contractAddress": "0xF6c1a36a200c9aCc5046A86037Ffbe4e0eCb2d6a", - "transactionIndex": 30, - "gasUsed": "2498884", - "logsBloom": "0x00000000000000000000000000000000000000000000001000000000000000000000000000000000000000000004000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000020000000000000000000800000000000000000000000000000000000004000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x9b80a015f2cde0d2673f140723459cb207d94c7956a9847a3f9a268244f9158e", - "transactionHash": "0xdfb3c52b30803839d449fa83c5fcfb24eb524d18c870e03ccca3b8d59161c31c", + "contractAddress": "0x0Ed143d1D6d98f10db7151b66D76aA3956072b5a", + "transactionIndex": 86, + "gasUsed": "2518562", + "logsBloom": "0x00000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000100000020000000000000000000800000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000100010000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x95e8e58e6bb9324431a63bc6fcfb7e1d40e7d882b995cb3b0d99ded0806f6a5a", + "transactionHash": "0x9a998931bf39359cbfc6c186f28b3741e10102738241891a53fb005f3e109a5e", "logs": [ { - "transactionIndex": 30, - "blockNumber": 11494700, - "transactionHash": "0xdfb3c52b30803839d449fa83c5fcfb24eb524d18c870e03ccca3b8d59161c31c", - "address": "0xF6c1a36a200c9aCc5046A86037Ffbe4e0eCb2d6a", + "transactionIndex": 86, + "blockNumber": 11603731, + "transactionHash": "0x9a998931bf39359cbfc6c186f28b3741e10102738241891a53fb005f3e109a5e", + "address": "0x0Ed143d1D6d98f10db7151b66D76aA3956072b5a", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000071f78361537a6f7b6818e7a760c8bc0146d93f50" ], "data": "0x", - "logIndex": 45, - "blockHash": "0x9b80a015f2cde0d2673f140723459cb207d94c7956a9847a3f9a268244f9158e" + "logIndex": 127, + "blockHash": "0x95e8e58e6bb9324431a63bc6fcfb7e1d40e7d882b995cb3b0d99ded0806f6a5a" } ], - "blockNumber": 11494700, - "cumulativeGasUsed": "4595212", + "blockNumber": 11603731, + "cumulativeGasUsed": "8156154", "status": 1, "byzantium": true }, "args": [], - "solcInputHash": "a0c4b4d689b13a774a7e3a992025a384", - "metadata": "{\"compiler\":{\"version\":\"0.5.11+commit.22be8592.mod\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAllStakes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"internalType\":\"struct SingleAssetStaking.Stake[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalOutstanding\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"setDurationRates\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_stakeType\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_rootHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_proofDepth\",\"type\":\"uint256\"}],\"name\":\"setAirDropRoot\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"name\":\"airDroppedStake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stakeWithSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"stakingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"durationRewardRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalCurrentHoldings\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalStaked\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"name\":\"airDroppedStakeClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"durations\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllDurations\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"dropRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingToken\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalExpectedRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllRates\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"yes\",\"type\":\"bool\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"durations\",\"type\":\"uint256[]\"}],\"name\":\"NewDurations\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"rates\",\"type\":\"uint256[]\"}],\"name\":\"NewRates\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"rootHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"proofDepth\",\"type\":\"uint256\"}],\"name\":\"NewAirDropRootHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])\":{\"details\":\"Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from an airdrop or a compensation program. Only 1 of each type is allowed per user. The proof must match the root hash\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"index\":\"Number that is zero base index of the stake in the payout entry\",\"merkleProof\":\"Array of proofs for that amount\",\"rate\":\"Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\",\"stakeType\":\"Number that represent the type of the stake, must not be 0 which is user stake\"}},\"airDroppedStakeClaimed(address,uint8)\":{\"details\":\"Has the airdropped stake already been claimed\"},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"durationRewardRate(uint256)\":{\"details\":\"Find the rate that corresponds to a given duration\",\"params\":{\"_duration\":\"Number of seconds\"}},\"exit()\":{\"details\":\"Exit out of all possible stakes\"},\"getAllStakes(address)\":{\"details\":\"Return all the stakes paid and unpaid for a given user\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,uint256[],uint256[])\":{\"details\":\"Initialize the contracts, sets up durations, rates, and preApprover for preApproved contracts can only be called once\",\"params\":{\"_durations\":\"Array of allowed durations in seconds\",\"_rates\":\"Array of rates(0.3 is 30%) that correspond to the allowed durations in 1e18 precision\",\"_stakingToken\":\"Address of the token that we are staking\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"setAirDropRoot(uint8,bytes32,uint256)\":{\"details\":\"Set air drop root for a specific stake type\",\"params\":{\"_proofDepth\":\"Depth of the Merklke Tree\",\"_rootHash\":\"Root hash of the Merkle Tree\",\"_stakeType\":\"Type of staking must be greater than 0\"}},\"setDurationRates(uint256[],uint256[])\":{\"details\":\"Set new durations and rates will not effect existing stakes\",\"params\":{\"_durations\":\"Array of durations in seconds\",\"_rates\":\"Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\"}},\"stake(uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. User must have already approved the contract for specified amount.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\"}},\"stakeWithSender(address,uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. This function can only be called by OGN token contract.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"staker\":\"Address of the account that is creating the stake\"}},\"totalCurrentHoldings(address)\":{\"details\":\"Calculate all current holdings of a user: staked value + prorated rewards\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalExpectedRewards(address)\":{\"details\":\"Calculate all the rewards a user can expect to receive.\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalStaked(address)\":{\"details\":\"Calculate all the staked value a user has put into the contract, rewards not included\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"transferGovernance(address)\":{\"details\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\",\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/staking/SingleAssetStaking.sol\":\"SingleAssetStaking\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x640b6dee7a4b830bdfd52b5031a07fc2b12209f5b2e29e5d364a7d37f69d8076\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\\n * the optional functions; to access them see {ERC20Detailed}.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xe5bb0f57cff3e299f360052ba50f1ea0fff046df2be070b6943e0e3c3fdad8a9\"},\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"../../math/SafeMath.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require((value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \\\"SafeERC20: decreased allowance below zero\\\");\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) { // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6f2c9955d65c522b80f4b8792f076512d2df947d2112cbc4d98a4781ed42ede2\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"pragma solidity ^0.5.5;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following \\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { codehash := extcodehash(account) }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1a8e5072509c5ea7365eb1d48030b9be865140c8fb779968da0a459a0e174a11\"},\"@openzeppelin/upgrades/contracts/Initializable.sol\":{\"content\":\"pragma solidity >=0.4.24 <0.7.0;\\n\\n\\n/**\\n * @title Initializable\\n *\\n * @dev Helper contract to support initializer functions. To use it, replace\\n * the constructor with a function that has the `initializer` modifier.\\n * WARNING: Unlike constructors, initializer functions must be manually\\n * invoked. This applies both to deploying an Initializable contract, as well\\n * as extending an Initializable contract via inheritance.\\n * WARNING: When used with inheritance, manual care must be taken to not invoke\\n * a parent initializer twice, or ensure that all initializers are idempotent,\\n * because this is not dealt with automatically as with constructors.\\n */\\ncontract Initializable {\\n\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to use in the initializer function of a contract.\\n */\\n modifier initializer() {\\n require(initializing || isConstructor() || !initialized, \\\"Contract instance has already been initialized\\\");\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n /// @dev Returns true if and only if the function is running in the constructor\\n function isConstructor() private view returns (bool) {\\n // extcodesize checks the size of the code stored in an address, and\\n // address returns the current address. Since the code is still not\\n // deployed when running a constructor, any checks on its code size will\\n // yield zero, making it an effective way to detect if a contract is\\n // under construction or not.\\n address self = address(this);\\n uint256 cs;\\n assembly { cs := extcodesize(self) }\\n return cs == 0;\\n }\\n\\n // Reserved storage space to allow for layout changes in the future.\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x9bfec92e36234ecc99b5d37230acb6cd1f99560233753162204104a4897e8721\"},\"contracts/governance/Governable.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\n/**\\n * @title OUSD Governable Contract\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32\\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32\\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32\\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() internal {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0x3e51ea48102945bf4b305bf9722a07514a585a29555d92f8c84352d1a4cfcee1\"},\"contracts/staking/SingleAssetStaking.sol\":{\"content\":\"pragma solidity 0.5.11;\\npragma experimental ABIEncoderV2;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\nimport {\\n Initializable\\n} from \\\"@openzeppelin/upgrades/contracts/Initializable.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\ncontract SingleAssetStaking is Initializable, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n /* ========== STATE VARIABLES ========== */\\n\\n IERC20 public stakingToken; // this is both the staking and rewards\\n\\n struct Stake {\\n uint256 amount; // amount to stake\\n uint256 end; // when does the staking period end\\n uint256 duration; // the duration of the stake\\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\\n bool paid;\\n uint8 stakeType;\\n }\\n\\n struct DropRoot {\\n bytes32 hash;\\n uint256 depth;\\n }\\n\\n uint256[] public durations; // allowed durations\\n uint256[] public rates; // rates that correspond with the allowed durations\\n\\n uint256 public totalOutstanding;\\n bool public paused;\\n\\n mapping(address => Stake[]) public userStakes;\\n\\n mapping(uint8 => DropRoot) public dropRoots;\\n\\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\\n uint8 constant USER_STAKE_TYPE = 0;\\n uint256 constant MAX_STAKES = 256;\\n\\n /* ========== Initialize ========== */\\n\\n /**\\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\\n * for preApproved contracts can only be called once\\n * @param _stakingToken Address of the token that we are staking\\n * @param _durations Array of allowed durations in seconds\\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\\n * durations in 1e18 precision\\n */\\n function initialize(\\n address _stakingToken,\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor initializer {\\n stakingToken = IERC20(_stakingToken);\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /* ========= Internal helper functions ======== */\\n\\n /**\\n * @dev Validate and set the duration and corresponding rates, will emit\\n * events NewRate and NewDurations\\n */\\n function _setDurationRates(\\n uint256[] memory _durations,\\n uint256[] memory _rates\\n ) internal {\\n require(\\n _rates.length == _durations.length,\\n \\\"Mismatch durations and rates\\\"\\n );\\n\\n for (uint256 i = 0; i < _rates.length; i++) {\\n require(_rates[i] < uint240(-1), \\\"Max rate exceeded\\\");\\n }\\n\\n rates = _rates;\\n durations = _durations;\\n\\n emit NewRates(msg.sender, rates);\\n emit NewDurations(msg.sender, durations);\\n }\\n\\n function _totalExpectedRewards(Stake[] storage stakes)\\n internal\\n view\\n returns (uint256 total)\\n {\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (!stake.paid) {\\n total = total.add(stake.amount.mulTruncate(stake.rate));\\n }\\n }\\n }\\n\\n function _totalExpected(Stake storage _stake)\\n internal\\n view\\n returns (uint256)\\n {\\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\\n }\\n\\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\\n internal\\n view\\n returns (bool)\\n {\\n Stake[] storage stakes = userStakes[account];\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (stakes[i].stakeType == stakeType) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n function _findDurationRate(uint256 duration)\\n internal\\n view\\n returns (uint240)\\n {\\n for (uint256 i = 0; i < durations.length; i++) {\\n if (duration == durations[i]) {\\n return uint240(rates[i]);\\n }\\n }\\n return 0;\\n }\\n\\n /**\\n * @dev Internal staking function\\n * will insert the stake into the stakes array and verify we have\\n * enough to pay off stake + reward\\n * @param staker Address of the staker\\n * @param stakeType Number that represent the type of the stake, 0 is user\\n * initiated all else is currently preApproved\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\\n * to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n */\\n function _stake(\\n address staker,\\n uint8 stakeType,\\n uint256 duration,\\n uint240 rate,\\n uint256 amount\\n ) internal {\\n require(!paused, \\\"Staking paused\\\");\\n\\n Stake[] storage stakes = userStakes[staker];\\n\\n uint256 end = block.timestamp.add(duration);\\n\\n uint256 i = stakes.length; // start at the end of the current array\\n\\n require(i < MAX_STAKES, \\\"Max stakes\\\");\\n\\n stakes.length += 1; // grow the array\\n // find the spot where we can insert the current stake\\n // this should make an increasing list sorted by end\\n while (i != 0 && stakes[i - 1].end > end) {\\n // shift it back one\\n stakes[i] = stakes[i - 1];\\n i -= 1;\\n }\\n\\n // insert the stake\\n Stake storage newStake = stakes[i];\\n newStake.rate = rate;\\n newStake.stakeType = stakeType;\\n newStake.end = end;\\n newStake.duration = duration;\\n newStake.amount = amount;\\n\\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\\n\\n emit Staked(staker, amount);\\n }\\n\\n function _stakeWithChecks(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) internal {\\n require(amount > 0, \\\"Cannot stake 0\\\");\\n\\n uint240 rewardRate = _findDurationRate(duration);\\n require(rewardRate > 0, \\\"Invalid duration\\\"); // we couldn't find the rate that correspond to the passed duration\\n\\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\\n // transfer in the token so that we can stake the correct amount\\n stakingToken.safeTransferFrom(staker, address(this), amount);\\n }\\n\\n modifier requireLiquidity() {\\n // we need to have enough balance to cover the rewards after the operation is complete\\n _;\\n require(\\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\\n \\\"Insufficient rewards\\\"\\n );\\n }\\n\\n /* ========== VIEWS ========== */\\n\\n function getAllDurations() external view returns (uint256[] memory) {\\n return durations;\\n }\\n\\n function getAllRates() external view returns (uint256[] memory) {\\n return rates;\\n }\\n\\n /**\\n * @dev Return all the stakes paid and unpaid for a given user\\n * @param account Address of the account that we want to look up\\n */\\n function getAllStakes(address account)\\n external\\n view\\n returns (Stake[] memory)\\n {\\n return userStakes[account];\\n }\\n\\n /**\\n * @dev Find the rate that corresponds to a given duration\\n * @param _duration Number of seconds\\n */\\n function durationRewardRate(uint256 _duration)\\n external\\n view\\n returns (uint256)\\n {\\n return _findDurationRate(_duration);\\n }\\n\\n /**\\n * @dev Has the airdropped stake already been claimed\\n */\\n function airDroppedStakeClaimed(address account, uint8 stakeType)\\n external\\n view\\n returns (bool)\\n {\\n return _airDroppedStakeClaimed(account, stakeType);\\n }\\n\\n /**\\n * @dev Calculate all the staked value a user has put into the contract,\\n * rewards not included\\n * @param account Address of the account that we want to look up\\n */\\n function totalStaked(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (!stakes[i].paid) {\\n total = total.add(stakes[i].amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Calculate all the rewards a user can expect to receive.\\n * @param account Address of the account that we want to look up\\n */\\n function totalExpectedRewards(address account)\\n external\\n view\\n returns (uint256)\\n {\\n return _totalExpectedRewards(userStakes[account]);\\n }\\n\\n /**\\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\\n * @param account Address of the account that we want to look up\\n */\\n function totalCurrentHoldings(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (stake.paid) {\\n continue;\\n } else if (stake.end < block.timestamp) {\\n total = total.add(_totalExpected(stake));\\n } else {\\n //calcualte the precentage accrued in term of rewards\\n total = total.add(\\n stake.amount.add(\\n stake.amount.mulTruncate(stake.rate).mulTruncate(\\n stake\\n .duration\\n .sub(stake.end.sub(block.timestamp))\\n .divPrecisely(stake.duration)\\n )\\n )\\n );\\n }\\n }\\n }\\n\\n /* ========== MUTATIVE FUNCTIONS ========== */\\n\\n /**\\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\\n * an airdrop or a compensation program.\\n * Only 1 of each type is allowed per user. The proof must match the root hash\\n * @param index Number that is zero base index of the stake in the payout entry\\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param merkleProof Array of proofs for that amount\\n */\\n function airDroppedStake(\\n uint256 index,\\n uint8 stakeType,\\n uint256 duration,\\n uint256 rate,\\n uint256 amount,\\n bytes32[] calldata merkleProof\\n ) external requireLiquidity {\\n require(stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n require(rate < uint240(-1), \\\"Max rate exceeded\\\");\\n require(index < 2**merkleProof.length, \\\"Invalid index\\\");\\n DropRoot storage dropRoot = dropRoots[stakeType];\\n require(merkleProof.length == dropRoot.depth, \\\"Invalid proof\\\");\\n\\n // Compute the merkle root\\n bytes32 node = keccak256(\\n abi.encodePacked(\\n index,\\n stakeType,\\n address(this),\\n msg.sender,\\n duration,\\n rate,\\n amount\\n )\\n );\\n uint256 path = index;\\n for (uint16 i = 0; i < merkleProof.length; i++) {\\n if ((path & 0x01) == 1) {\\n node = keccak256(abi.encodePacked(merkleProof[i], node));\\n } else {\\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\\n }\\n path /= 2;\\n }\\n\\n // Check the merkle proof\\n require(node == dropRoot.hash, \\\"Stake not approved\\\");\\n\\n // verify that we haven't already staked\\n require(\\n !_airDroppedStakeClaimed(msg.sender, stakeType),\\n \\\"Already staked\\\"\\n );\\n\\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract.\\n * User must have already approved the contract for specified amount.\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\\n // no checks are performed in this function since those are already present in _stakeWithChecks\\n _stakeWithChecks(msg.sender, amount, duration);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract. This function\\n * can only be called by OGN token contract.\\n * @param staker Address of the account that is creating the stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stakeWithSender(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) external returns (bool) {\\n require(\\n msg.sender == address(stakingToken),\\n \\\"Only token contract can make this call\\\"\\n );\\n\\n _stakeWithChecks(staker, amount, duration);\\n return true;\\n }\\n\\n /**\\n * @dev Exit out of all possible stakes\\n */\\n function exit() external requireLiquidity {\\n Stake[] storage stakes = userStakes[msg.sender];\\n require(stakes.length > 0, \\\"Nothing staked\\\");\\n\\n uint256 totalWithdraw = 0;\\n uint256 l = stakes.length;\\n do {\\n Stake storage exitStake = stakes[l - 1];\\n // stop on the first ended stake that's already been paid\\n if (exitStake.end < block.timestamp && exitStake.paid) {\\n break;\\n }\\n //might not be ended\\n if (exitStake.end < block.timestamp) {\\n //we are paying out the stake\\n exitStake.paid = true;\\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\\n }\\n l--;\\n } while (l > 0);\\n require(totalWithdraw > 0, \\\"All stakes in lock-up\\\");\\n\\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\\n emit Withdrawn(msg.sender, totalWithdraw);\\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\\n }\\n\\n /* ========== MODIFIERS ========== */\\n\\n function setPaused(bool _paused) external onlyGovernor {\\n paused = _paused;\\n emit Paused(msg.sender, paused);\\n }\\n\\n /**\\n * @dev Set new durations and rates will not effect existing stakes\\n * @param _durations Array of durations in seconds\\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\\n */\\n function setDurationRates(\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor {\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /**\\n * @dev Set air drop root for a specific stake type\\n * @param _stakeType Type of staking must be greater than 0\\n * @param _rootHash Root hash of the Merkle Tree\\n * @param _proofDepth Depth of the Merklke Tree\\n */\\n function setAirDropRoot(\\n uint8 _stakeType,\\n bytes32 _rootHash,\\n uint256 _proofDepth\\n ) external onlyGovernor {\\n require(_stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n dropRoots[_stakeType].hash = _rootHash;\\n dropRoots[_stakeType].depth = _proofDepth;\\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\\n }\\n\\n /* ========== EVENTS ========== */\\n\\n event Staked(address indexed user, uint256 amount);\\n event Withdrawn(address indexed user, uint256 amount);\\n event Paused(address indexed user, bool yes);\\n event NewDurations(address indexed user, uint256[] durations);\\n event NewRates(address indexed user, uint256[] rates);\\n event NewAirDropRootHash(\\n uint8 stakeType,\\n bytes32 rootHash,\\n uint256 proofDepth\\n );\\n}\\n\",\"keccak256\":\"0xc6efc99f88cb18fb16135e61b60d5b5b2afa061003c665cbc91b4bed635bae51\"},\"contracts/utils/StableMath.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\\n */\\n function scaleBy(uint256 x, int8 adjustment)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (adjustment > 0) {\\n x = x.mul(10**uint256(adjustment));\\n } else if (adjustment < 0) {\\n x = x.div(10**uint256(adjustment * -1));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e38 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0xa77fccf850feb6d54ba3a6530f92554caef8a67a1ceb573d4f8a5d1bf64ff9d2\"}},\"version\":1}", - "bytecode": "0x608060405262000018336001600160e01b036200007116565b6200002b6001600160e01b036200008416565b6001600160a01b031660006001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a362000098565b60008051602062002c7283398151915255565b60008051602062002c728339815191525490565b612bca80620000a86000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c4e565b6103c5565b6040516101ce919061280d565b60405180910390f35b6101df610487565b6040516101ce91906127bc565b6101f4610497565b6040516101ce91906129fb565b61021461020f366004611e1a565b61049d565b005b610214610224366004611daa565b610519565b610214610237366004611f74565b6105b0565b61021461024a366004611eb1565b610650565b6102576108db565b6040516101ce9190612840565b6102146108e4565b61025761027a366004611d2d565b610927565b61028761096a565b6040516101ce919061285c565b6102146102a2366004611e92565b610979565b6101f46102b5366004611e56565b610a29565b6101f46102c8366004611c4e565b610a43565b6101f46102db366004611c4e565b610b62565b6102576102ee366004611d7a565b610bec565b610306610301366004611cf3565b610c01565b6040516101ce96959493929190612a09565b6101f4610326366004611e56565b610c63565b610333610c81565b6040516101ce919061281e565b610257610cd9565b610214610356366004611c4e565b610cfc565b6101f4610369366004611e56565b610d73565b61038161037c366004611f56565b610d80565b6040516101ce92919061284e565b61021461039d366004611c6c565b610d99565b610214610eca565b6101f46103b8366004611c4e565b6110c0565b6103336110e1565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611137565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128cb565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612840565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128cb565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061115c92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128cb565b60ff83166105f45760405162461bcd60e51b81526004016104c19061288b565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612a63565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c19061288b565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c19061290b565b600281900a87106106b95760405162461bcd60e51b81526004016104c1906128db565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129ab565b6000888830338a8a8a60405160200161070d9796959493929190612741565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c92919061270f565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b292919061270f565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129cb565b610804338a61127f565b156108215760405162461bcd60e51b81526004016104c19061296b565b61082e338a8a8a8a6112f4565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127bc565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e74565b10156108d25760405162461bcd60e51b81526004016104c19061299b565b50505050505050565b60375460ff1681565b6108ec61153d565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c1906129db565b61092533611562565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c1906128eb565b61095f8484846115db565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115db565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127bc565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e74565b1015610a255760405162461bcd60e51b81526004016104c19061299b565b5050565b6000610a348261165d565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116bb565b859063ffffffff6116e116565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461170690919063ffffffff16565b60028801549063ffffffff61170616565b9063ffffffff61174816565b60038501548554610b34916001600160f01b031663ffffffff61177d16565b9063ffffffff61177d16565b83549063ffffffff6116e116565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116e116565b92505b600101610b7c565b6000610bf8838361127f565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611137565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128cb565b610d2981611792565b806001600160a01b0316610d3b611137565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128cb565b600054610100900460ff1680610dd65750610dd66117b6565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c19061298b565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061115c92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c19061297b565b80546000905b6000836001830381548110610f0e57fe5b90600052602060002090600402019050428160010154108015610f3c57506003810154600160f01b900460ff165b15610f475750610f8f565b4281600101541015610f845760038101805460ff60f01b1916600160f01b179055610f81610f74826116bb565b849063ffffffff6116e116565b92505b506000190180610efd575b60008211610faf5760405162461bcd60e51b81526004016104c19061294b565b603654610fc2908363ffffffff61170616565b60365560405133907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590610ff79085906129fb565b60405180910390a260335461101c906001600160a01b0316338463ffffffff6117bc16565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906110529030906004016127bc565b60206040518083038186803b15801561106a57600080fd5b505afa15801561107e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110a29190810190611e74565b10156109255760405162461bcd60e51b81526004016104c19061299b565b6001600160a01b0381166000908152603860205260408120610bfb9061181a565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461117d5760405162461bcd60e51b81526004016104c19061291b565b60005b81518110156111ce576000196001600160f01b03168282815181106111a157fe5b6020026020010151106111c65760405162461bcd60e51b81526004016104c19061290b565b600101611180565b5080516111e2906035906020840190611b04565b5081516111f6906034906020850190611b04565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c36035604051611231919061282f565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d46034604051611273919061282f565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112e9578360ff168282815481106112b257fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112e157600192505050610bfb565b600101611299565b506000949350505050565b60375460ff16156113175760405162461bcd60e51b81526004016104c19061293b565b6001600160a01b038516600090815260386020526040812090611340428663ffffffff6116e116565b825490915061010081106113665760405162461bcd60e51b81526004016104c19061287b565b82546001016113758482611b4f565b505b80158015906113a557508183600183038154811061139157fe5b906000526020600020906004020160010154115b1561146f578260018203815481106113b957fe5b90600052602060002090600402018382815481106113d357fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611377565b600083828154811061147d57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114ec6114dd826116bb565b6036549063ffffffff6116e116565b6036556040516001600160a01b038a16907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9061152a9088906129fb565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b0381166115885760405162461bcd60e51b81526004016104c19061292b565b806001600160a01b031661159a611137565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115d881611891565b50565b600082116115fb5760405162461bcd60e51b81526004016104c1906128ab565b60006116068261165d565b90506000816001600160f01b0316116116315760405162461bcd60e51b81526004016104c19061289b565b61163f8460008484876112f4565b6033546105aa906001600160a01b031685308663ffffffff6118b516565b6000805b6034548110156116b2576034818154811061167857fe5b90600052602060002001548314156116aa576035818154811061169757fe5b9060005260206000200154915050610482565b600101611661565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61177d16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128bb565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118d9565b60008061176384670de0b6b3a764000063ffffffff61190516565b9050611775818463ffffffff61193f16565b949350505050565b6000610bf88383670de0b6b3a7640000611981565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161181590849063a9059cbb60e01b906117de90869086906024016127f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119af565b505050565b6000805b825481101561188b57600083828154811061183557fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff16611882576003810154815461187f91610f7491906001600160f01b031663ffffffff61177d16565b92505b5060010161181e565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117de908790879087906024016127ca565b600081848411156118fd5760405162461bcd60e51b81526004016104c1919061286a565b505050900390565b60008261191457506000610bfb565b8282028284828161192157fe5b0414610bf85760405162461bcd60e51b81526004016104c19061295b565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611a94565b600080611994858563ffffffff61190516565b90506119a6818463ffffffff61193f16565b95945050505050565b6119c1826001600160a01b0316611acb565b6119dd5760405162461bcd60e51b81526004016104c1906129eb565b60006060836001600160a01b0316836040516119f99190612735565b6000604051808303816000865af19150503d8060008114611a36576040519150601f19603f3d011682016040523d82523d6000602084013e611a3b565b606091505b509150915081611a5d5760405162461bcd60e51b81526004016104c1906128fb565b8051156105aa5780806020019051611a789190810190611e38565b6105aa5760405162461bcd60e51b81526004016104c1906129bb565b60008183611ab55760405162461bcd60e51b81526004016104c1919061286a565b506000838581611ac157fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611775575050151592915050565b828054828255906000526020600020908101928215611b3f579160200282015b82811115611b3f578251825591602001919060010190611b24565b50611b4b929150611b7b565b5090565b815481835581811115611815576004028160040283600052602060002091820191016118159190611b95565b61049491905b80821115611b4b5760008155600101611b81565b61049491905b80821115611b4b57600080825560018201819055600282018190556003820155600401611b9b565b8035610bfb81612b58565b60008083601f840112611be057600080fd5b50813567ffffffffffffffff811115611bf857600080fd5b602083019150836020820283011115611c1057600080fd5b9250929050565b8035610bfb81612b6c565b8051610bfb81612b6c565b8035610bfb81612b75565b8051610bfb81612b75565b8035610bfb81612b7e565b600060208284031215611c6057600080fd5b60006117758484611bc3565b600080600080600060608688031215611c8457600080fd5b6000611c908888611bc3565b955050602086013567ffffffffffffffff811115611cad57600080fd5b611cb988828901611bce565b9450945050604086013567ffffffffffffffff811115611cd857600080fd5b611ce488828901611bce565b92509250509295509295909350565b60008060408385031215611d0657600080fd5b6000611d128585611bc3565b9250506020611d2385828601611c2d565b9150509250929050565b600080600060608486031215611d4257600080fd5b6000611d4e8686611bc3565b9350506020611d5f86828701611c2d565b9250506040611d7086828701611c2d565b9150509250925092565b60008060408385031215611d8d57600080fd5b6000611d998585611bc3565b9250506020611d2385828601611c43565b60008060008060408587031215611dc057600080fd5b843567ffffffffffffffff811115611dd757600080fd5b611de387828801611bce565b9450945050602085013567ffffffffffffffff811115611e0257600080fd5b611e0e87828801611bce565b95989497509550505050565b600060208284031215611e2c57600080fd5b60006117758484611c17565b600060208284031215611e4a57600080fd5b60006117758484611c22565b600060208284031215611e6857600080fd5b60006117758484611c2d565b600060208284031215611e8657600080fd5b60006117758484611c38565b60008060408385031215611ea557600080fd5b6000611d128585611c2d565b600080600080600080600060c0888a031215611ecc57600080fd5b6000611ed88a8a611c2d565b9750506020611ee98a828b01611c43565b9650506040611efa8a828b01611c2d565b9550506060611f0b8a828b01611c2d565b9450506080611f1c8a828b01611c2d565b93505060a088013567ffffffffffffffff811115611f3957600080fd5b611f458a828b01611bce565b925092505092959891949750929550565b600060208284031215611f6857600080fd5b60006117758484611c43565b600080600060608486031215611f8957600080fd5b6000611d4e8686611c43565b6000611fa1838361267c565b505060c00190565b6000611fb583836120e2565b505060200190565b611fce611fc982612aa7565b612b1a565b82525050565b611fce81612aa7565b6000611fe882612a90565b611ff28185612a9e565b9350611ffd83612a7e565b8060005b8381101561202b5781516120158882611f95565b975061202083612a7e565b925050600101612001565b509495945050505050565b600061204182612a90565b61204b8185612a9e565b935061205683612a7e565b8060005b8381101561202b57815161206e8882611fa9565b975061207983612a7e565b92505060010161205a565b600061208f82612a94565b6120998185612a9e565b93506120a483612a84565b8060005b8381101561202b576120b982612b36565b6120c38882611fa9565b97506120ce83612a98565b9250506001016120a8565b611fce81612ab2565b611fce81610494565b611fce6120f782610494565b610494565b600061210782612a90565b6121118185610482565b9350612121818560208601612ae0565b9290920192915050565b611fce81612ad5565b600061213f82612a90565b6121498185612a9e565b9350612159818560208601612ae0565b61216281612b42565b9093019392505050565b6000612179600a83612a9e565b694d6178207374616b657360b01b815260200192915050565b600061219f601883612a9e565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121d8601083612a9e565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612204600e83612a9e565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061222e601b83612a9e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612267601a83612a9e565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122a0600d83612a9e565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122c9602683612a9e565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612311602083612a9e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061234a601183612a9e565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612377601c83612a9e565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123b0601a83612a9e565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b60006123e9600e83612a9e565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612413601583612a9e565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612444602183612a9e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612487600e83612a9e565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124b1600e83612a9e565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124db602e83612a9e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061252b601483612a9e565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061255b600d83612a9e565b6c24b73b30b634b210383937b7b360991b815260200192915050565b6000612584602a83612a9e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125d0601283612a9e565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b60006125fe603083612a9e565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b6000612650601f83612a9e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c083019061268d84826120e2565b5060208201516126a060208501826120e2565b5060408201516126b360408501826120e2565b5060608201516126c660608501826126ec565b5060808201516126d960808501826120d9565b5060a08201516105aa60a08501826126f5565b611fce81612ac3565b611fce81612acf565b611fce61270a82612acf565b612b2b565b600061271b82856120eb565b60208201915061272b82846120eb565b5060200192915050565b600061096382846120fc565b600061274d828a6120eb565b60208201915061275d82896126fe565b60018201915061276d8288611fbd565b60148201915061277d8287611fbd565b60148201915061278d82866120eb565b60208201915061279d82856120eb565b6020820191506127ad82846120eb565b50602001979650505050505050565b60208101610bfb8284611fd4565b606081016127d88286611fd4565b6127e56020830185611fd4565b61177560408301846120e2565b604081016128008285611fd4565b61096360208301846120e2565b60208082528101610bf88184611fdd565b60208082528101610bf88184612036565b60208082528101610bf88184612084565b60208101610bfb82846120d9565b6040810161280082856120e2565b60208101610bfb828461212b565b60208082528101610bf88184612134565b60208082528101610bfb8161216c565b60208082528101610bfb81612192565b60208082528101610bfb816121cb565b60208082528101610bfb816121f7565b60208082528101610bfb81612221565b60208082528101610bfb8161225a565b60208082528101610bfb81612293565b60208082528101610bfb816122bc565b60208082528101610bfb81612304565b60208082528101610bfb8161233d565b60208082528101610bfb8161236a565b60208082528101610bfb816123a3565b60208082528101610bfb816123dc565b60208082528101610bfb81612406565b60208082528101610bfb81612437565b60208082528101610bfb8161247a565b60208082528101610bfb816124a4565b60208082528101610bfb816124ce565b60208082528101610bfb8161251e565b60208082528101610bfb8161254e565b60208082528101610bfb81612577565b60208082528101610bfb816125c3565b60208082528101610bfb816125f1565b60208082528101610bfb81612643565b60208101610bfb82846120e2565b60c08101612a1782896120e2565b612a2460208301886120e2565b612a3160408301876120e2565b612a3e60608301866126ec565b612a4b60808301856120d9565b612a5860a08301846126f5565b979650505050505050565b60608101612a7182866126f5565b6127e560208301856120e2565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612ab7565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612aa7565b60005b83811015612afb578181015183820152602001612ae3565b838111156105aa5750506000910152565b6000610bfb6120f783610494565b6000610bfb826000610bfb82612b52565b6000610bfb82612b4c565b6000610bfb8254612b0c565b601f01601f191690565b60f81b90565b60601b90565b612b6181612aa7565b81146115d857600080fd5b612b6181612ab2565b612b6181610494565b612b6181612acf56fea365627a7a723158203b8a45a1f9626792470b52e91b20e9152e303efcdb1c49cbfeeff74029c015c96c6578706572696d656e74616cf564736f6c634300050b00407bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c4e565b6103c5565b6040516101ce919061280d565b60405180910390f35b6101df610487565b6040516101ce91906127bc565b6101f4610497565b6040516101ce91906129fb565b61021461020f366004611e1a565b61049d565b005b610214610224366004611daa565b610519565b610214610237366004611f74565b6105b0565b61021461024a366004611eb1565b610650565b6102576108db565b6040516101ce9190612840565b6102146108e4565b61025761027a366004611d2d565b610927565b61028761096a565b6040516101ce919061285c565b6102146102a2366004611e92565b610979565b6101f46102b5366004611e56565b610a29565b6101f46102c8366004611c4e565b610a43565b6101f46102db366004611c4e565b610b62565b6102576102ee366004611d7a565b610bec565b610306610301366004611cf3565b610c01565b6040516101ce96959493929190612a09565b6101f4610326366004611e56565b610c63565b610333610c81565b6040516101ce919061281e565b610257610cd9565b610214610356366004611c4e565b610cfc565b6101f4610369366004611e56565b610d73565b61038161037c366004611f56565b610d80565b6040516101ce92919061284e565b61021461039d366004611c6c565b610d99565b610214610eca565b6101f46103b8366004611c4e565b6110c0565b6103336110e1565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611137565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128cb565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612840565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128cb565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061115c92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128cb565b60ff83166105f45760405162461bcd60e51b81526004016104c19061288b565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612a63565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c19061288b565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c19061290b565b600281900a87106106b95760405162461bcd60e51b81526004016104c1906128db565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129ab565b6000888830338a8a8a60405160200161070d9796959493929190612741565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c92919061270f565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b292919061270f565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129cb565b610804338a61127f565b156108215760405162461bcd60e51b81526004016104c19061296b565b61082e338a8a8a8a6112f4565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127bc565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e74565b10156108d25760405162461bcd60e51b81526004016104c19061299b565b50505050505050565b60375460ff1681565b6108ec61153d565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c1906129db565b61092533611562565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c1906128eb565b61095f8484846115db565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115db565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127bc565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e74565b1015610a255760405162461bcd60e51b81526004016104c19061299b565b5050565b6000610a348261165d565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116bb565b859063ffffffff6116e116565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461170690919063ffffffff16565b60028801549063ffffffff61170616565b9063ffffffff61174816565b60038501548554610b34916001600160f01b031663ffffffff61177d16565b9063ffffffff61177d16565b83549063ffffffff6116e116565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116e116565b92505b600101610b7c565b6000610bf8838361127f565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611137565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128cb565b610d2981611792565b806001600160a01b0316610d3b611137565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128cb565b600054610100900460ff1680610dd65750610dd66117b6565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c19061298b565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061115c92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c19061297b565b80546000905b6000836001830381548110610f0e57fe5b90600052602060002090600402019050428160010154108015610f3c57506003810154600160f01b900460ff165b15610f475750610f8f565b4281600101541015610f845760038101805460ff60f01b1916600160f01b179055610f81610f74826116bb565b849063ffffffff6116e116565b92505b506000190180610efd575b60008211610faf5760405162461bcd60e51b81526004016104c19061294b565b603654610fc2908363ffffffff61170616565b60365560405133907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590610ff79085906129fb565b60405180910390a260335461101c906001600160a01b0316338463ffffffff6117bc16565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906110529030906004016127bc565b60206040518083038186803b15801561106a57600080fd5b505afa15801561107e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110a29190810190611e74565b10156109255760405162461bcd60e51b81526004016104c19061299b565b6001600160a01b0381166000908152603860205260408120610bfb9061181a565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461117d5760405162461bcd60e51b81526004016104c19061291b565b60005b81518110156111ce576000196001600160f01b03168282815181106111a157fe5b6020026020010151106111c65760405162461bcd60e51b81526004016104c19061290b565b600101611180565b5080516111e2906035906020840190611b04565b5081516111f6906034906020850190611b04565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c36035604051611231919061282f565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d46034604051611273919061282f565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112e9578360ff168282815481106112b257fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112e157600192505050610bfb565b600101611299565b506000949350505050565b60375460ff16156113175760405162461bcd60e51b81526004016104c19061293b565b6001600160a01b038516600090815260386020526040812090611340428663ffffffff6116e116565b825490915061010081106113665760405162461bcd60e51b81526004016104c19061287b565b82546001016113758482611b4f565b505b80158015906113a557508183600183038154811061139157fe5b906000526020600020906004020160010154115b1561146f578260018203815481106113b957fe5b90600052602060002090600402018382815481106113d357fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611377565b600083828154811061147d57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114ec6114dd826116bb565b6036549063ffffffff6116e116565b6036556040516001600160a01b038a16907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9061152a9088906129fb565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b0381166115885760405162461bcd60e51b81526004016104c19061292b565b806001600160a01b031661159a611137565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115d881611891565b50565b600082116115fb5760405162461bcd60e51b81526004016104c1906128ab565b60006116068261165d565b90506000816001600160f01b0316116116315760405162461bcd60e51b81526004016104c19061289b565b61163f8460008484876112f4565b6033546105aa906001600160a01b031685308663ffffffff6118b516565b6000805b6034548110156116b2576034818154811061167857fe5b90600052602060002001548314156116aa576035818154811061169757fe5b9060005260206000200154915050610482565b600101611661565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61177d16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128bb565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118d9565b60008061176384670de0b6b3a764000063ffffffff61190516565b9050611775818463ffffffff61193f16565b949350505050565b6000610bf88383670de0b6b3a7640000611981565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161181590849063a9059cbb60e01b906117de90869086906024016127f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119af565b505050565b6000805b825481101561188b57600083828154811061183557fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff16611882576003810154815461187f91610f7491906001600160f01b031663ffffffff61177d16565b92505b5060010161181e565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117de908790879087906024016127ca565b600081848411156118fd5760405162461bcd60e51b81526004016104c1919061286a565b505050900390565b60008261191457506000610bfb565b8282028284828161192157fe5b0414610bf85760405162461bcd60e51b81526004016104c19061295b565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611a94565b600080611994858563ffffffff61190516565b90506119a6818463ffffffff61193f16565b95945050505050565b6119c1826001600160a01b0316611acb565b6119dd5760405162461bcd60e51b81526004016104c1906129eb565b60006060836001600160a01b0316836040516119f99190612735565b6000604051808303816000865af19150503d8060008114611a36576040519150601f19603f3d011682016040523d82523d6000602084013e611a3b565b606091505b509150915081611a5d5760405162461bcd60e51b81526004016104c1906128fb565b8051156105aa5780806020019051611a789190810190611e38565b6105aa5760405162461bcd60e51b81526004016104c1906129bb565b60008183611ab55760405162461bcd60e51b81526004016104c1919061286a565b506000838581611ac157fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611775575050151592915050565b828054828255906000526020600020908101928215611b3f579160200282015b82811115611b3f578251825591602001919060010190611b24565b50611b4b929150611b7b565b5090565b815481835581811115611815576004028160040283600052602060002091820191016118159190611b95565b61049491905b80821115611b4b5760008155600101611b81565b61049491905b80821115611b4b57600080825560018201819055600282018190556003820155600401611b9b565b8035610bfb81612b58565b60008083601f840112611be057600080fd5b50813567ffffffffffffffff811115611bf857600080fd5b602083019150836020820283011115611c1057600080fd5b9250929050565b8035610bfb81612b6c565b8051610bfb81612b6c565b8035610bfb81612b75565b8051610bfb81612b75565b8035610bfb81612b7e565b600060208284031215611c6057600080fd5b60006117758484611bc3565b600080600080600060608688031215611c8457600080fd5b6000611c908888611bc3565b955050602086013567ffffffffffffffff811115611cad57600080fd5b611cb988828901611bce565b9450945050604086013567ffffffffffffffff811115611cd857600080fd5b611ce488828901611bce565b92509250509295509295909350565b60008060408385031215611d0657600080fd5b6000611d128585611bc3565b9250506020611d2385828601611c2d565b9150509250929050565b600080600060608486031215611d4257600080fd5b6000611d4e8686611bc3565b9350506020611d5f86828701611c2d565b9250506040611d7086828701611c2d565b9150509250925092565b60008060408385031215611d8d57600080fd5b6000611d998585611bc3565b9250506020611d2385828601611c43565b60008060008060408587031215611dc057600080fd5b843567ffffffffffffffff811115611dd757600080fd5b611de387828801611bce565b9450945050602085013567ffffffffffffffff811115611e0257600080fd5b611e0e87828801611bce565b95989497509550505050565b600060208284031215611e2c57600080fd5b60006117758484611c17565b600060208284031215611e4a57600080fd5b60006117758484611c22565b600060208284031215611e6857600080fd5b60006117758484611c2d565b600060208284031215611e8657600080fd5b60006117758484611c38565b60008060408385031215611ea557600080fd5b6000611d128585611c2d565b600080600080600080600060c0888a031215611ecc57600080fd5b6000611ed88a8a611c2d565b9750506020611ee98a828b01611c43565b9650506040611efa8a828b01611c2d565b9550506060611f0b8a828b01611c2d565b9450506080611f1c8a828b01611c2d565b93505060a088013567ffffffffffffffff811115611f3957600080fd5b611f458a828b01611bce565b925092505092959891949750929550565b600060208284031215611f6857600080fd5b60006117758484611c43565b600080600060608486031215611f8957600080fd5b6000611d4e8686611c43565b6000611fa1838361267c565b505060c00190565b6000611fb583836120e2565b505060200190565b611fce611fc982612aa7565b612b1a565b82525050565b611fce81612aa7565b6000611fe882612a90565b611ff28185612a9e565b9350611ffd83612a7e565b8060005b8381101561202b5781516120158882611f95565b975061202083612a7e565b925050600101612001565b509495945050505050565b600061204182612a90565b61204b8185612a9e565b935061205683612a7e565b8060005b8381101561202b57815161206e8882611fa9565b975061207983612a7e565b92505060010161205a565b600061208f82612a94565b6120998185612a9e565b93506120a483612a84565b8060005b8381101561202b576120b982612b36565b6120c38882611fa9565b97506120ce83612a98565b9250506001016120a8565b611fce81612ab2565b611fce81610494565b611fce6120f782610494565b610494565b600061210782612a90565b6121118185610482565b9350612121818560208601612ae0565b9290920192915050565b611fce81612ad5565b600061213f82612a90565b6121498185612a9e565b9350612159818560208601612ae0565b61216281612b42565b9093019392505050565b6000612179600a83612a9e565b694d6178207374616b657360b01b815260200192915050565b600061219f601883612a9e565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121d8601083612a9e565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612204600e83612a9e565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061222e601b83612a9e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612267601a83612a9e565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122a0600d83612a9e565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122c9602683612a9e565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612311602083612a9e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061234a601183612a9e565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612377601c83612a9e565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123b0601a83612a9e565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b60006123e9600e83612a9e565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612413601583612a9e565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612444602183612a9e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612487600e83612a9e565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124b1600e83612a9e565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124db602e83612a9e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061252b601483612a9e565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061255b600d83612a9e565b6c24b73b30b634b210383937b7b360991b815260200192915050565b6000612584602a83612a9e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125d0601283612a9e565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b60006125fe603083612a9e565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b6000612650601f83612a9e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c083019061268d84826120e2565b5060208201516126a060208501826120e2565b5060408201516126b360408501826120e2565b5060608201516126c660608501826126ec565b5060808201516126d960808501826120d9565b5060a08201516105aa60a08501826126f5565b611fce81612ac3565b611fce81612acf565b611fce61270a82612acf565b612b2b565b600061271b82856120eb565b60208201915061272b82846120eb565b5060200192915050565b600061096382846120fc565b600061274d828a6120eb565b60208201915061275d82896126fe565b60018201915061276d8288611fbd565b60148201915061277d8287611fbd565b60148201915061278d82866120eb565b60208201915061279d82856120eb565b6020820191506127ad82846120eb565b50602001979650505050505050565b60208101610bfb8284611fd4565b606081016127d88286611fd4565b6127e56020830185611fd4565b61177560408301846120e2565b604081016128008285611fd4565b61096360208301846120e2565b60208082528101610bf88184611fdd565b60208082528101610bf88184612036565b60208082528101610bf88184612084565b60208101610bfb82846120d9565b6040810161280082856120e2565b60208101610bfb828461212b565b60208082528101610bf88184612134565b60208082528101610bfb8161216c565b60208082528101610bfb81612192565b60208082528101610bfb816121cb565b60208082528101610bfb816121f7565b60208082528101610bfb81612221565b60208082528101610bfb8161225a565b60208082528101610bfb81612293565b60208082528101610bfb816122bc565b60208082528101610bfb81612304565b60208082528101610bfb8161233d565b60208082528101610bfb8161236a565b60208082528101610bfb816123a3565b60208082528101610bfb816123dc565b60208082528101610bfb81612406565b60208082528101610bfb81612437565b60208082528101610bfb8161247a565b60208082528101610bfb816124a4565b60208082528101610bfb816124ce565b60208082528101610bfb8161251e565b60208082528101610bfb8161254e565b60208082528101610bfb81612577565b60208082528101610bfb816125c3565b60208082528101610bfb816125f1565b60208082528101610bfb81612643565b60208101610bfb82846120e2565b60c08101612a1782896120e2565b612a2460208301886120e2565b612a3160408301876120e2565b612a3e60608301866126ec565b612a4b60808301856120d9565b612a5860a08301846126f5565b979650505050505050565b60608101612a7182866126f5565b6127e560208301856120e2565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612ab7565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612aa7565b60005b83811015612afb578181015183820152602001612ae3565b838111156105aa5750506000910152565b6000610bfb6120f783610494565b6000610bfb826000610bfb82612b52565b6000610bfb82612b4c565b6000610bfb8254612b0c565b601f01601f191690565b60f81b90565b60601b90565b612b6181612aa7565b81146115d857600080fd5b612b6181612ab2565b612b6181610494565b612b6181612acf56fea365627a7a723158203b8a45a1f9626792470b52e91b20e9152e303efcdb1c49cbfeeff74029c015c96c6578706572696d656e74616cf564736f6c634300050b0040", + "solcInputHash": "c7459e40fa663addef2a13f82ab72194", + "metadata": "{\"compiler\":{\"version\":\"0.5.11+commit.22be8592.mod\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAllStakes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"internalType\":\"struct SingleAssetStaking.Stake[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalOutstanding\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"setDurationRates\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_stakeType\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_rootHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_proofDepth\",\"type\":\"uint256\"}],\"name\":\"setAirDropRoot\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"name\":\"airDroppedStake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stakeWithSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"stakingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"durationRewardRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalCurrentHoldings\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalStaked\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"name\":\"airDroppedStakeClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"durations\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllDurations\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"dropRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingToken\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalExpectedRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllRates\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"yes\",\"type\":\"bool\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"durations\",\"type\":\"uint256[]\"}],\"name\":\"NewDurations\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"rates\",\"type\":\"uint256[]\"}],\"name\":\"NewRates\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"rootHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"proofDepth\",\"type\":\"uint256\"}],\"name\":\"NewAirDropRootHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])\":{\"details\":\"Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from an airdrop or a compensation program. Only 1 of each type is allowed per user. The proof must match the root hash\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"index\":\"Number that is zero base index of the stake in the payout entry\",\"merkleProof\":\"Array of proofs for that amount\",\"rate\":\"Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\",\"stakeType\":\"Number that represent the type of the stake, must not be 0 which is user stake\"}},\"airDroppedStakeClaimed(address,uint8)\":{\"details\":\"Has the airdropped stake already been claimed\"},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"durationRewardRate(uint256)\":{\"details\":\"Find the rate that corresponds to a given duration\",\"params\":{\"_duration\":\"Number of seconds\"}},\"exit()\":{\"details\":\"Exit out of all possible stakes\"},\"getAllStakes(address)\":{\"details\":\"Return all the stakes paid and unpaid for a given user\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,uint256[],uint256[])\":{\"details\":\"Initialize the contracts, sets up durations, rates, and preApprover for preApproved contracts can only be called once\",\"params\":{\"_durations\":\"Array of allowed durations in seconds\",\"_rates\":\"Array of rates(0.3 is 30%) that correspond to the allowed durations in 1e18 precision\",\"_stakingToken\":\"Address of the token that we are staking\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"setAirDropRoot(uint8,bytes32,uint256)\":{\"details\":\"Set air drop root for a specific stake type\",\"params\":{\"_proofDepth\":\"Depth of the Merklke Tree\",\"_rootHash\":\"Root hash of the Merkle Tree\",\"_stakeType\":\"Type of staking must be greater than 0\"}},\"setDurationRates(uint256[],uint256[])\":{\"details\":\"Set new durations and rates will not effect existing stakes\",\"params\":{\"_durations\":\"Array of durations in seconds\",\"_rates\":\"Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\"}},\"stake(uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. User must have already approved the contract for specified amount.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\"}},\"stakeWithSender(address,uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. This function can only be called by OGN token contract.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"staker\":\"Address of the account that is creating the stake\"}},\"totalCurrentHoldings(address)\":{\"details\":\"Calculate all current holdings of a user: staked value + prorated rewards\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalExpectedRewards(address)\":{\"details\":\"Calculate all the rewards a user can expect to receive.\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalStaked(address)\":{\"details\":\"Calculate all the staked value a user has put into the contract, rewards not included\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"transferGovernance(address)\":{\"details\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\",\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/staking/SingleAssetStaking.sol\":\"SingleAssetStaking\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x640b6dee7a4b830bdfd52b5031a07fc2b12209f5b2e29e5d364a7d37f69d8076\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\\n * the optional functions; to access them see {ERC20Detailed}.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xe5bb0f57cff3e299f360052ba50f1ea0fff046df2be070b6943e0e3c3fdad8a9\"},\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"../../math/SafeMath.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require((value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \\\"SafeERC20: decreased allowance below zero\\\");\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) { // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6f2c9955d65c522b80f4b8792f076512d2df947d2112cbc4d98a4781ed42ede2\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"pragma solidity ^0.5.5;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following \\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { codehash := extcodehash(account) }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1a8e5072509c5ea7365eb1d48030b9be865140c8fb779968da0a459a0e174a11\"},\"@openzeppelin/upgrades/contracts/Initializable.sol\":{\"content\":\"pragma solidity >=0.4.24 <0.7.0;\\n\\n\\n/**\\n * @title Initializable\\n *\\n * @dev Helper contract to support initializer functions. To use it, replace\\n * the constructor with a function that has the `initializer` modifier.\\n * WARNING: Unlike constructors, initializer functions must be manually\\n * invoked. This applies both to deploying an Initializable contract, as well\\n * as extending an Initializable contract via inheritance.\\n * WARNING: When used with inheritance, manual care must be taken to not invoke\\n * a parent initializer twice, or ensure that all initializers are idempotent,\\n * because this is not dealt with automatically as with constructors.\\n */\\ncontract Initializable {\\n\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to use in the initializer function of a contract.\\n */\\n modifier initializer() {\\n require(initializing || isConstructor() || !initialized, \\\"Contract instance has already been initialized\\\");\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n /// @dev Returns true if and only if the function is running in the constructor\\n function isConstructor() private view returns (bool) {\\n // extcodesize checks the size of the code stored in an address, and\\n // address returns the current address. Since the code is still not\\n // deployed when running a constructor, any checks on its code size will\\n // yield zero, making it an effective way to detect if a contract is\\n // under construction or not.\\n address self = address(this);\\n uint256 cs;\\n assembly { cs := extcodesize(self) }\\n return cs == 0;\\n }\\n\\n // Reserved storage space to allow for layout changes in the future.\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x9bfec92e36234ecc99b5d37230acb6cd1f99560233753162204104a4897e8721\"},\"contracts/governance/Governable.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\n/**\\n * @title OUSD Governable Contract\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32\\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32\\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32\\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() internal {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0x3e51ea48102945bf4b305bf9722a07514a585a29555d92f8c84352d1a4cfcee1\"},\"contracts/staking/SingleAssetStaking.sol\":{\"content\":\"pragma solidity 0.5.11;\\npragma experimental ABIEncoderV2;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\nimport {\\n Initializable\\n} from \\\"@openzeppelin/upgrades/contracts/Initializable.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\ncontract SingleAssetStaking is Initializable, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n /* ========== STATE VARIABLES ========== */\\n\\n IERC20 public stakingToken; // this is both the staking and rewards\\n\\n struct Stake {\\n uint256 amount; // amount to stake\\n uint256 end; // when does the staking period end\\n uint256 duration; // the duration of the stake\\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\\n bool paid;\\n uint8 stakeType;\\n }\\n\\n struct DropRoot {\\n bytes32 hash;\\n uint256 depth;\\n }\\n\\n uint256[] public durations; // allowed durations\\n uint256[] public rates; // rates that correspond with the allowed durations\\n\\n uint256 public totalOutstanding;\\n bool public paused;\\n\\n mapping(address => Stake[]) public userStakes;\\n\\n mapping(uint8 => DropRoot) public dropRoots;\\n\\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\\n uint8 constant USER_STAKE_TYPE = 0;\\n uint256 constant MAX_STAKES = 256;\\n\\n /* ========== Initialize ========== */\\n\\n /**\\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\\n * for preApproved contracts can only be called once\\n * @param _stakingToken Address of the token that we are staking\\n * @param _durations Array of allowed durations in seconds\\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\\n * durations in 1e18 precision\\n */\\n function initialize(\\n address _stakingToken,\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor initializer {\\n stakingToken = IERC20(_stakingToken);\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /* ========= Internal helper functions ======== */\\n\\n /**\\n * @dev Validate and set the duration and corresponding rates, will emit\\n * events NewRate and NewDurations\\n */\\n function _setDurationRates(\\n uint256[] memory _durations,\\n uint256[] memory _rates\\n ) internal {\\n require(\\n _rates.length == _durations.length,\\n \\\"Mismatch durations and rates\\\"\\n );\\n\\n for (uint256 i = 0; i < _rates.length; i++) {\\n require(_rates[i] < uint240(-1), \\\"Max rate exceeded\\\");\\n }\\n\\n rates = _rates;\\n durations = _durations;\\n\\n emit NewRates(msg.sender, rates);\\n emit NewDurations(msg.sender, durations);\\n }\\n\\n function _totalExpectedRewards(Stake[] storage stakes)\\n internal\\n view\\n returns (uint256 total)\\n {\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (!stake.paid) {\\n total = total.add(stake.amount.mulTruncate(stake.rate));\\n }\\n }\\n }\\n\\n function _totalExpected(Stake storage _stake)\\n internal\\n view\\n returns (uint256)\\n {\\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\\n }\\n\\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\\n internal\\n view\\n returns (bool)\\n {\\n Stake[] storage stakes = userStakes[account];\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (stakes[i].stakeType == stakeType) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n function _findDurationRate(uint256 duration)\\n internal\\n view\\n returns (uint240)\\n {\\n for (uint256 i = 0; i < durations.length; i++) {\\n if (duration == durations[i]) {\\n return uint240(rates[i]);\\n }\\n }\\n return 0;\\n }\\n\\n /**\\n * @dev Internal staking function\\n * will insert the stake into the stakes array and verify we have\\n * enough to pay off stake + reward\\n * @param staker Address of the staker\\n * @param stakeType Number that represent the type of the stake, 0 is user\\n * initiated all else is currently preApproved\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\\n * to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n */\\n function _stake(\\n address staker,\\n uint8 stakeType,\\n uint256 duration,\\n uint240 rate,\\n uint256 amount\\n ) internal {\\n require(!paused, \\\"Staking paused\\\");\\n\\n Stake[] storage stakes = userStakes[staker];\\n\\n uint256 end = block.timestamp.add(duration);\\n\\n uint256 i = stakes.length; // start at the end of the current array\\n\\n require(i < MAX_STAKES, \\\"Max stakes\\\");\\n\\n stakes.length += 1; // grow the array\\n // find the spot where we can insert the current stake\\n // this should make an increasing list sorted by end\\n while (i != 0 && stakes[i - 1].end > end) {\\n // shift it back one\\n stakes[i] = stakes[i - 1];\\n i -= 1;\\n }\\n\\n // insert the stake\\n Stake storage newStake = stakes[i];\\n newStake.rate = rate;\\n newStake.stakeType = stakeType;\\n newStake.end = end;\\n newStake.duration = duration;\\n newStake.amount = amount;\\n\\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\\n\\n emit Staked(staker, amount, duration, rate);\\n }\\n\\n function _stakeWithChecks(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) internal {\\n require(amount > 0, \\\"Cannot stake 0\\\");\\n\\n uint240 rewardRate = _findDurationRate(duration);\\n require(rewardRate > 0, \\\"Invalid duration\\\"); // we couldn't find the rate that correspond to the passed duration\\n\\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\\n // transfer in the token so that we can stake the correct amount\\n stakingToken.safeTransferFrom(staker, address(this), amount);\\n }\\n\\n modifier requireLiquidity() {\\n // we need to have enough balance to cover the rewards after the operation is complete\\n _;\\n require(\\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\\n \\\"Insufficient rewards\\\"\\n );\\n }\\n\\n /* ========== VIEWS ========== */\\n\\n function getAllDurations() external view returns (uint256[] memory) {\\n return durations;\\n }\\n\\n function getAllRates() external view returns (uint256[] memory) {\\n return rates;\\n }\\n\\n /**\\n * @dev Return all the stakes paid and unpaid for a given user\\n * @param account Address of the account that we want to look up\\n */\\n function getAllStakes(address account)\\n external\\n view\\n returns (Stake[] memory)\\n {\\n return userStakes[account];\\n }\\n\\n /**\\n * @dev Find the rate that corresponds to a given duration\\n * @param _duration Number of seconds\\n */\\n function durationRewardRate(uint256 _duration)\\n external\\n view\\n returns (uint256)\\n {\\n return _findDurationRate(_duration);\\n }\\n\\n /**\\n * @dev Has the airdropped stake already been claimed\\n */\\n function airDroppedStakeClaimed(address account, uint8 stakeType)\\n external\\n view\\n returns (bool)\\n {\\n return _airDroppedStakeClaimed(account, stakeType);\\n }\\n\\n /**\\n * @dev Calculate all the staked value a user has put into the contract,\\n * rewards not included\\n * @param account Address of the account that we want to look up\\n */\\n function totalStaked(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (!stakes[i].paid) {\\n total = total.add(stakes[i].amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Calculate all the rewards a user can expect to receive.\\n * @param account Address of the account that we want to look up\\n */\\n function totalExpectedRewards(address account)\\n external\\n view\\n returns (uint256)\\n {\\n return _totalExpectedRewards(userStakes[account]);\\n }\\n\\n /**\\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\\n * @param account Address of the account that we want to look up\\n */\\n function totalCurrentHoldings(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (stake.paid) {\\n continue;\\n } else if (stake.end < block.timestamp) {\\n total = total.add(_totalExpected(stake));\\n } else {\\n //calcualte the precentage accrued in term of rewards\\n total = total.add(\\n stake.amount.add(\\n stake.amount.mulTruncate(stake.rate).mulTruncate(\\n stake\\n .duration\\n .sub(stake.end.sub(block.timestamp))\\n .divPrecisely(stake.duration)\\n )\\n )\\n );\\n }\\n }\\n }\\n\\n /* ========== MUTATIVE FUNCTIONS ========== */\\n\\n /**\\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\\n * an airdrop or a compensation program.\\n * Only 1 of each type is allowed per user. The proof must match the root hash\\n * @param index Number that is zero base index of the stake in the payout entry\\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param merkleProof Array of proofs for that amount\\n */\\n function airDroppedStake(\\n uint256 index,\\n uint8 stakeType,\\n uint256 duration,\\n uint256 rate,\\n uint256 amount,\\n bytes32[] calldata merkleProof\\n ) external requireLiquidity {\\n require(stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n require(rate < uint240(-1), \\\"Max rate exceeded\\\");\\n require(index < 2**merkleProof.length, \\\"Invalid index\\\");\\n DropRoot storage dropRoot = dropRoots[stakeType];\\n require(merkleProof.length == dropRoot.depth, \\\"Invalid proof\\\");\\n\\n // Compute the merkle root\\n bytes32 node = keccak256(\\n abi.encodePacked(\\n index,\\n stakeType,\\n address(this),\\n msg.sender,\\n duration,\\n rate,\\n amount\\n )\\n );\\n uint256 path = index;\\n for (uint16 i = 0; i < merkleProof.length; i++) {\\n if ((path & 0x01) == 1) {\\n node = keccak256(abi.encodePacked(merkleProof[i], node));\\n } else {\\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\\n }\\n path /= 2;\\n }\\n\\n // Check the merkle proof\\n require(node == dropRoot.hash, \\\"Stake not approved\\\");\\n\\n // verify that we haven't already staked\\n require(\\n !_airDroppedStakeClaimed(msg.sender, stakeType),\\n \\\"Already staked\\\"\\n );\\n\\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract.\\n * User must have already approved the contract for specified amount.\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\\n // no checks are performed in this function since those are already present in _stakeWithChecks\\n _stakeWithChecks(msg.sender, amount, duration);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract. This function\\n * can only be called by OGN token contract.\\n * @param staker Address of the account that is creating the stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stakeWithSender(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) external returns (bool) {\\n require(\\n msg.sender == address(stakingToken),\\n \\\"Only token contract can make this call\\\"\\n );\\n\\n _stakeWithChecks(staker, amount, duration);\\n return true;\\n }\\n\\n /**\\n * @dev Exit out of all possible stakes\\n */\\n function exit() external requireLiquidity {\\n Stake[] storage stakes = userStakes[msg.sender];\\n require(stakes.length > 0, \\\"Nothing staked\\\");\\n\\n uint256 totalWithdraw = 0;\\n uint256 stakedAmount = 0;\\n uint256 l = stakes.length;\\n do {\\n Stake storage exitStake = stakes[l - 1];\\n // stop on the first ended stake that's already been paid\\n if (exitStake.end < block.timestamp && exitStake.paid) {\\n break;\\n }\\n //might not be ended\\n if (exitStake.end < block.timestamp) {\\n //we are paying out the stake\\n exitStake.paid = true;\\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\\n stakedAmount = stakedAmount.add(exitStake.amount);\\n }\\n l--;\\n } while (l > 0);\\n require(totalWithdraw > 0, \\\"All stakes in lock-up\\\");\\n\\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\\n }\\n\\n /* ========== MODIFIERS ========== */\\n\\n function setPaused(bool _paused) external onlyGovernor {\\n paused = _paused;\\n emit Paused(msg.sender, paused);\\n }\\n\\n /**\\n * @dev Set new durations and rates will not effect existing stakes\\n * @param _durations Array of durations in seconds\\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\\n */\\n function setDurationRates(\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor {\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /**\\n * @dev Set air drop root for a specific stake type\\n * @param _stakeType Type of staking must be greater than 0\\n * @param _rootHash Root hash of the Merkle Tree\\n * @param _proofDepth Depth of the Merklke Tree\\n */\\n function setAirDropRoot(\\n uint8 _stakeType,\\n bytes32 _rootHash,\\n uint256 _proofDepth\\n ) external onlyGovernor {\\n require(_stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n dropRoots[_stakeType].hash = _rootHash;\\n dropRoots[_stakeType].depth = _proofDepth;\\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\\n }\\n\\n /* ========== EVENTS ========== */\\n\\n event Staked(\\n address indexed user,\\n uint256 amount,\\n uint256 duration,\\n uint256 rate\\n );\\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\\n event Paused(address indexed user, bool yes);\\n event NewDurations(address indexed user, uint256[] durations);\\n event NewRates(address indexed user, uint256[] rates);\\n event NewAirDropRootHash(\\n uint8 stakeType,\\n bytes32 rootHash,\\n uint256 proofDepth\\n );\\n}\\n\",\"keccak256\":\"0x397ead290428160d0e34a9d74a54d68498d8ad12d8329c3b576b0fcacae17b2e\"},\"contracts/utils/StableMath.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\\n */\\n function scaleBy(uint256 x, int8 adjustment)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (adjustment > 0) {\\n x = x.mul(10**uint256(adjustment));\\n } else if (adjustment < 0) {\\n x = x.div(10**uint256(adjustment * -1));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e38 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0xa77fccf850feb6d54ba3a6530f92554caef8a67a1ceb573d4f8a5d1bf64ff9d2\"}},\"version\":1}", + "bytecode": "0x608060405262000018336001600160e01b036200007116565b6200002b6001600160e01b036200008416565b6001600160a01b031660006001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a362000098565b60008051602062002ccd83398151915255565b60008051602062002ccd8339815191525490565b612c2580620000a86000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c6d565b6103c5565b6040516101ce9190612835565b60405180910390f35b6101df610487565b6040516101ce91906127e4565b6101f4610497565b6040516101ce9190612a23565b61021461020f366004611e39565b61049d565b005b610214610224366004611dc9565b610519565b610214610237366004611f93565b6105b0565b61021461024a366004611ed0565b610650565b6102576108db565b6040516101ce9190612868565b6102146108e4565b61025761027a366004611d4c565b610927565b61028761096a565b6040516101ce9190612884565b6102146102a2366004611eb1565b610979565b6101f46102b5366004611e75565b610a29565b6101f46102c8366004611c6d565b610a43565b6101f46102db366004611c6d565b610b62565b6102576102ee366004611d99565b610bec565b610306610301366004611d12565b610c01565b6040516101ce96959493929190612a59565b6101f4610326366004611e75565b610c63565b610333610c81565b6040516101ce9190612846565b610257610cd9565b610214610356366004611c6d565b610cfc565b6101f4610369366004611e75565b610d73565b61038161037c366004611f75565b610d80565b6040516101ce929190612876565b61021461039d366004611c8b565b610d99565b610214610eca565b6101f46103b8366004611c6d565b6110ce565b6103336110ef565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611145565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128f3565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612868565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128f3565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061116a92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128f3565b60ff83166105f45760405162461bcd60e51b81526004016104c1906128b3565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612ab3565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c1906128b3565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c190612933565b600281900a87106106b95760405162461bcd60e51b81526004016104c190612903565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129d3565b6000888830338a8a8a60405160200161070d9796959493929190612769565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c929190612737565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b2929190612737565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129f3565b610804338a61128d565b156108215760405162461bcd60e51b81526004016104c190612993565b61082e338a8a8a8a611302565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127e4565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e93565b10156108d25760405162461bcd60e51b81526004016104c1906129c3565b50505050505050565b60375460ff1681565b6108ec61154f565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c190612a03565b61092533611574565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c190612913565b61095f8484846115ed565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115ed565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127e4565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e93565b1015610a255760405162461bcd60e51b81526004016104c1906129c3565b5050565b6000610a348261166f565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116cd565b859063ffffffff6116f316565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461171890919063ffffffff16565b60028801549063ffffffff61171816565b9063ffffffff61175a16565b60038501548554610b34916001600160f01b031663ffffffff61178f16565b9063ffffffff61178f16565b83549063ffffffff6116f316565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116f316565b92505b600101610b7c565b6000610bf8838361128d565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611145565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128f3565b610d29816117a4565b806001600160a01b0316610d3b611145565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128f3565b600054610100900460ff1680610dd65750610dd66117c8565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c1906129b3565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061116a92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c1906129a3565b805460009081905b6000846001830381548110610f1057fe5b90600052602060002090600402019050428160010154108015610f3e57506003810154600160f01b900460ff165b15610f495750610f9a565b4281600101541015610f8f5760038101805460ff60f01b1916600160f01b179055610f76610ab9826116cd565b8154909450610f8c90849063ffffffff6116f316565b92505b506000190180610eff575b60008311610fba5760405162461bcd60e51b81526004016104c190612973565b603654610fcd908463ffffffff61171816565b60365560405133907f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6906110049086908690612876565b60405180910390a2603354611029906001600160a01b0316338563ffffffff6117ce16565b50506036546033546040516370a0823160e01b81529193506001600160a01b031691506370a08231906110609030906004016127e4565b60206040518083038186803b15801561107857600080fd5b505afa15801561108c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110b09190810190611e93565b10156109255760405162461bcd60e51b81526004016104c1906129c3565b6001600160a01b0381166000908152603860205260408120610bfb9061182c565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461118b5760405162461bcd60e51b81526004016104c190612943565b60005b81518110156111dc576000196001600160f01b03168282815181106111af57fe5b6020026020010151106111d45760405162461bcd60e51b81526004016104c190612933565b60010161118e565b5080516111f0906035906020840190611b23565b508151611204906034906020850190611b23565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c3603560405161123f9190612857565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d460346040516112819190612857565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112f7578360ff168282815481106112c057fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112ef57600192505050610bfb565b6001016112a7565b506000949350505050565b60375460ff16156113255760405162461bcd60e51b81526004016104c190612963565b6001600160a01b03851660009081526038602052604081209061134e428663ffffffff6116f316565b825490915061010081106113745760405162461bcd60e51b81526004016104c1906128a3565b82546001016113838482611b6e565b505b80158015906113b357508183600183038154811061139f57fe5b906000526020600020906004020160010154115b1561147d578260018203815481106113c757fe5b90600052602060002090600402018382815481106113e157fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611385565b600083828154811061148b57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114fa6114eb826116cd565b6036549063ffffffff6116f316565b6036556040516001600160a01b038a16907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9061153c9088908b908b90612a31565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b03811661159a5760405162461bcd60e51b81526004016104c190612953565b806001600160a01b03166115ac611145565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115ea816118b0565b50565b6000821161160d5760405162461bcd60e51b81526004016104c1906128d3565b60006116188261166f565b90506000816001600160f01b0316116116435760405162461bcd60e51b81526004016104c1906128c3565b611651846000848487611302565b6033546105aa906001600160a01b031685308663ffffffff6118d416565b6000805b6034548110156116c4576034818154811061168a57fe5b90600052602060002001548314156116bc57603581815481106116a957fe5b9060005260206000200154915050610482565b600101611673565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61178f16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128e3565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118f8565b60008061177584670de0b6b3a764000063ffffffff61192416565b9050611787818463ffffffff61195e16565b949350505050565b6000610bf88383670de0b6b3a76400006119a0565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161182790849063a9059cbb60e01b906117f0908690869060240161281a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119ce565b505050565b6000805b82548110156118aa57600083828154811061184757fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff166118a1576003810154815461189e9161189191906001600160f01b031663ffffffff61178f16565b849063ffffffff6116f316565b92505b50600101611830565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117f0908790879087906024016127f2565b6000818484111561191c5760405162461bcd60e51b81526004016104c19190612892565b505050900390565b60008261193357506000610bfb565b8282028284828161194057fe5b0414610bf85760405162461bcd60e51b81526004016104c190612983565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611ab3565b6000806119b3858563ffffffff61192416565b90506119c5818463ffffffff61195e16565b95945050505050565b6119e0826001600160a01b0316611aea565b6119fc5760405162461bcd60e51b81526004016104c190612a13565b60006060836001600160a01b031683604051611a18919061275d565b6000604051808303816000865af19150503d8060008114611a55576040519150601f19603f3d011682016040523d82523d6000602084013e611a5a565b606091505b509150915081611a7c5760405162461bcd60e51b81526004016104c190612923565b8051156105aa5780806020019051611a979190810190611e57565b6105aa5760405162461bcd60e51b81526004016104c1906129e3565b60008183611ad45760405162461bcd60e51b81526004016104c19190612892565b506000838581611ae057fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611787575050151592915050565b828054828255906000526020600020908101928215611b5e579160200282015b82811115611b5e578251825591602001919060010190611b43565b50611b6a929150611b9a565b5090565b815481835581811115611827576004028160040283600052602060002091820191016118279190611bb4565b61049491905b80821115611b6a5760008155600101611ba0565b61049491905b80821115611b6a57600080825560018201819055600282018190556003820155600401611bba565b8035610bfb81612bb3565b60008083601f840112611bff57600080fd5b50813567ffffffffffffffff811115611c1757600080fd5b602083019150836020820283011115611c2f57600080fd5b9250929050565b8035610bfb81612bc7565b8051610bfb81612bc7565b8035610bfb81612bd0565b8051610bfb81612bd0565b8035610bfb81612bd9565b600060208284031215611c7f57600080fd5b60006117878484611be2565b600080600080600060608688031215611ca357600080fd5b6000611caf8888611be2565b955050602086013567ffffffffffffffff811115611ccc57600080fd5b611cd888828901611bed565b9450945050604086013567ffffffffffffffff811115611cf757600080fd5b611d0388828901611bed565b92509250509295509295909350565b60008060408385031215611d2557600080fd5b6000611d318585611be2565b9250506020611d4285828601611c4c565b9150509250929050565b600080600060608486031215611d6157600080fd5b6000611d6d8686611be2565b9350506020611d7e86828701611c4c565b9250506040611d8f86828701611c4c565b9150509250925092565b60008060408385031215611dac57600080fd5b6000611db88585611be2565b9250506020611d4285828601611c62565b60008060008060408587031215611ddf57600080fd5b843567ffffffffffffffff811115611df657600080fd5b611e0287828801611bed565b9450945050602085013567ffffffffffffffff811115611e2157600080fd5b611e2d87828801611bed565b95989497509550505050565b600060208284031215611e4b57600080fd5b60006117878484611c36565b600060208284031215611e6957600080fd5b60006117878484611c41565b600060208284031215611e8757600080fd5b60006117878484611c4c565b600060208284031215611ea557600080fd5b60006117878484611c57565b60008060408385031215611ec457600080fd5b6000611d318585611c4c565b600080600080600080600060c0888a031215611eeb57600080fd5b6000611ef78a8a611c4c565b9750506020611f088a828b01611c62565b9650506040611f198a828b01611c4c565b9550506060611f2a8a828b01611c4c565b9450506080611f3b8a828b01611c4c565b93505060a088013567ffffffffffffffff811115611f5857600080fd5b611f648a828b01611bed565b925092505092959891949750929550565b600060208284031215611f8757600080fd5b60006117878484611c62565b600080600060608486031215611fa857600080fd5b6000611d6d8686611c62565b6000611fc0838361269b565b505060c00190565b6000611fd48383612101565b505060200190565b611fed611fe882612af7565b612b75565b82525050565b611fed81612af7565b600061200782612ae0565b6120118185612aee565b935061201c83612ace565b8060005b8381101561204a5781516120348882611fb4565b975061203f83612ace565b925050600101612020565b509495945050505050565b600061206082612ae0565b61206a8185612aee565b935061207583612ace565b8060005b8381101561204a57815161208d8882611fc8565b975061209883612ace565b925050600101612079565b60006120ae82612ae4565b6120b88185612aee565b93506120c383612ad4565b8060005b8381101561204a576120d882612b91565b6120e28882611fc8565b97506120ed83612ae8565b9250506001016120c7565b611fed81612b02565b611fed81610494565b611fed61211682610494565b610494565b600061212682612ae0565b6121308185610482565b9350612140818560208601612b3b565b9290920192915050565b611fed81612b25565b600061215e82612ae0565b6121688185612aee565b9350612178818560208601612b3b565b61218181612b9d565b9093019392505050565b6000612198600a83612aee565b694d6178207374616b657360b01b815260200192915050565b60006121be601883612aee565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121f7601083612aee565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612223600e83612aee565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061224d601b83612aee565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612286601a83612aee565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122bf600d83612aee565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122e8602683612aee565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612330602083612aee565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612369601183612aee565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612396601c83612aee565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123cf601a83612aee565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b6000612408600e83612aee565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612432601583612aee565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612463602183612aee565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006124a6600e83612aee565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124d0600e83612aee565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124fa602e83612aee565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061254a601483612aee565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061257a600d83612aee565b6c24b73b30b634b210383937b7b360991b815260200192915050565b60006125a3602a83612aee565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125ef601283612aee565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b600061261d603083612aee565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b600061266f601f83612aee565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c08301906126ac8482612101565b5060208201516126bf6020850182612101565b5060408201516126d26040850182612101565b5060608201516126e5606085018261270b565b5060808201516126f860808501826120f8565b5060a08201516105aa60a085018261271d565b611fed81612b13565b611fed81612b30565b611fed81612b1f565b611fed61273282612b1f565b612b86565b6000612743828561210a565b602082019150612753828461210a565b5060200192915050565b6000610963828461211b565b6000612775828a61210a565b6020820191506127858289612726565b6001820191506127958288611fdc565b6014820191506127a58287611fdc565b6014820191506127b5828661210a565b6020820191506127c5828561210a565b6020820191506127d5828461210a565b50602001979650505050505050565b60208101610bfb8284611ff3565b606081016128008286611ff3565b61280d6020830185611ff3565b6117876040830184612101565b604081016128288285611ff3565b6109636020830184612101565b60208082528101610bf88184611ffc565b60208082528101610bf88184612055565b60208082528101610bf881846120a3565b60208101610bfb82846120f8565b604081016128288285612101565b60208101610bfb828461214a565b60208082528101610bf88184612153565b60208082528101610bfb8161218b565b60208082528101610bfb816121b1565b60208082528101610bfb816121ea565b60208082528101610bfb81612216565b60208082528101610bfb81612240565b60208082528101610bfb81612279565b60208082528101610bfb816122b2565b60208082528101610bfb816122db565b60208082528101610bfb81612323565b60208082528101610bfb8161235c565b60208082528101610bfb81612389565b60208082528101610bfb816123c2565b60208082528101610bfb816123fb565b60208082528101610bfb81612425565b60208082528101610bfb81612456565b60208082528101610bfb81612499565b60208082528101610bfb816124c3565b60208082528101610bfb816124ed565b60208082528101610bfb8161253d565b60208082528101610bfb8161256d565b60208082528101610bfb81612596565b60208082528101610bfb816125e2565b60208082528101610bfb81612610565b60208082528101610bfb81612662565b60208101610bfb8284612101565b60608101612a3f8286612101565b612a4c6020830185612101565b6117876040830184612714565b60c08101612a678289612101565b612a746020830188612101565b612a816040830187612101565b612a8e606083018661270b565b612a9b60808301856120f8565b612aa860a083018461271d565b979650505050505050565b60608101612ac1828661271d565b61280d6020830185612101565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612b07565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612af7565b6000610bfb82612b13565b60005b83811015612b56578181015183820152602001612b3e565b838111156105aa5750506000910152565b6000610bfb61211683610494565b6000610bfb826000610bfb82612bad565b6000610bfb82612ba7565b6000610bfb8254612b67565b601f01601f191690565b60f81b90565b60601b90565b612bbc81612af7565b81146115ea57600080fd5b612bbc81612b02565b612bbc81610494565b612bbc81612b1f56fea365627a7a723158200dfb3e06c3cb37079851ef4ebb60b603ca03e591e2736b87fa908d68d042d6576c6578706572696d656e74616cf564736f6c634300050b00407bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c6d565b6103c5565b6040516101ce9190612835565b60405180910390f35b6101df610487565b6040516101ce91906127e4565b6101f4610497565b6040516101ce9190612a23565b61021461020f366004611e39565b61049d565b005b610214610224366004611dc9565b610519565b610214610237366004611f93565b6105b0565b61021461024a366004611ed0565b610650565b6102576108db565b6040516101ce9190612868565b6102146108e4565b61025761027a366004611d4c565b610927565b61028761096a565b6040516101ce9190612884565b6102146102a2366004611eb1565b610979565b6101f46102b5366004611e75565b610a29565b6101f46102c8366004611c6d565b610a43565b6101f46102db366004611c6d565b610b62565b6102576102ee366004611d99565b610bec565b610306610301366004611d12565b610c01565b6040516101ce96959493929190612a59565b6101f4610326366004611e75565b610c63565b610333610c81565b6040516101ce9190612846565b610257610cd9565b610214610356366004611c6d565b610cfc565b6101f4610369366004611e75565b610d73565b61038161037c366004611f75565b610d80565b6040516101ce929190612876565b61021461039d366004611c8b565b610d99565b610214610eca565b6101f46103b8366004611c6d565b6110ce565b6103336110ef565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611145565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128f3565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612868565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128f3565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061116a92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128f3565b60ff83166105f45760405162461bcd60e51b81526004016104c1906128b3565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612ab3565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c1906128b3565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c190612933565b600281900a87106106b95760405162461bcd60e51b81526004016104c190612903565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129d3565b6000888830338a8a8a60405160200161070d9796959493929190612769565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c929190612737565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b2929190612737565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129f3565b610804338a61128d565b156108215760405162461bcd60e51b81526004016104c190612993565b61082e338a8a8a8a611302565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127e4565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e93565b10156108d25760405162461bcd60e51b81526004016104c1906129c3565b50505050505050565b60375460ff1681565b6108ec61154f565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c190612a03565b61092533611574565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c190612913565b61095f8484846115ed565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115ed565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127e4565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e93565b1015610a255760405162461bcd60e51b81526004016104c1906129c3565b5050565b6000610a348261166f565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116cd565b859063ffffffff6116f316565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461171890919063ffffffff16565b60028801549063ffffffff61171816565b9063ffffffff61175a16565b60038501548554610b34916001600160f01b031663ffffffff61178f16565b9063ffffffff61178f16565b83549063ffffffff6116f316565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116f316565b92505b600101610b7c565b6000610bf8838361128d565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611145565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128f3565b610d29816117a4565b806001600160a01b0316610d3b611145565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128f3565b600054610100900460ff1680610dd65750610dd66117c8565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c1906129b3565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061116a92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c1906129a3565b805460009081905b6000846001830381548110610f1057fe5b90600052602060002090600402019050428160010154108015610f3e57506003810154600160f01b900460ff165b15610f495750610f9a565b4281600101541015610f8f5760038101805460ff60f01b1916600160f01b179055610f76610ab9826116cd565b8154909450610f8c90849063ffffffff6116f316565b92505b506000190180610eff575b60008311610fba5760405162461bcd60e51b81526004016104c190612973565b603654610fcd908463ffffffff61171816565b60365560405133907f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6906110049086908690612876565b60405180910390a2603354611029906001600160a01b0316338563ffffffff6117ce16565b50506036546033546040516370a0823160e01b81529193506001600160a01b031691506370a08231906110609030906004016127e4565b60206040518083038186803b15801561107857600080fd5b505afa15801561108c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110b09190810190611e93565b10156109255760405162461bcd60e51b81526004016104c1906129c3565b6001600160a01b0381166000908152603860205260408120610bfb9061182c565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461118b5760405162461bcd60e51b81526004016104c190612943565b60005b81518110156111dc576000196001600160f01b03168282815181106111af57fe5b6020026020010151106111d45760405162461bcd60e51b81526004016104c190612933565b60010161118e565b5080516111f0906035906020840190611b23565b508151611204906034906020850190611b23565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c3603560405161123f9190612857565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d460346040516112819190612857565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112f7578360ff168282815481106112c057fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112ef57600192505050610bfb565b6001016112a7565b506000949350505050565b60375460ff16156113255760405162461bcd60e51b81526004016104c190612963565b6001600160a01b03851660009081526038602052604081209061134e428663ffffffff6116f316565b825490915061010081106113745760405162461bcd60e51b81526004016104c1906128a3565b82546001016113838482611b6e565b505b80158015906113b357508183600183038154811061139f57fe5b906000526020600020906004020160010154115b1561147d578260018203815481106113c757fe5b90600052602060002090600402018382815481106113e157fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611385565b600083828154811061148b57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114fa6114eb826116cd565b6036549063ffffffff6116f316565b6036556040516001600160a01b038a16907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9061153c9088908b908b90612a31565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b03811661159a5760405162461bcd60e51b81526004016104c190612953565b806001600160a01b03166115ac611145565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115ea816118b0565b50565b6000821161160d5760405162461bcd60e51b81526004016104c1906128d3565b60006116188261166f565b90506000816001600160f01b0316116116435760405162461bcd60e51b81526004016104c1906128c3565b611651846000848487611302565b6033546105aa906001600160a01b031685308663ffffffff6118d416565b6000805b6034548110156116c4576034818154811061168a57fe5b90600052602060002001548314156116bc57603581815481106116a957fe5b9060005260206000200154915050610482565b600101611673565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61178f16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128e3565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118f8565b60008061177584670de0b6b3a764000063ffffffff61192416565b9050611787818463ffffffff61195e16565b949350505050565b6000610bf88383670de0b6b3a76400006119a0565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161182790849063a9059cbb60e01b906117f0908690869060240161281a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119ce565b505050565b6000805b82548110156118aa57600083828154811061184757fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff166118a1576003810154815461189e9161189191906001600160f01b031663ffffffff61178f16565b849063ffffffff6116f316565b92505b50600101611830565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117f0908790879087906024016127f2565b6000818484111561191c5760405162461bcd60e51b81526004016104c19190612892565b505050900390565b60008261193357506000610bfb565b8282028284828161194057fe5b0414610bf85760405162461bcd60e51b81526004016104c190612983565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611ab3565b6000806119b3858563ffffffff61192416565b90506119c5818463ffffffff61195e16565b95945050505050565b6119e0826001600160a01b0316611aea565b6119fc5760405162461bcd60e51b81526004016104c190612a13565b60006060836001600160a01b031683604051611a18919061275d565b6000604051808303816000865af19150503d8060008114611a55576040519150601f19603f3d011682016040523d82523d6000602084013e611a5a565b606091505b509150915081611a7c5760405162461bcd60e51b81526004016104c190612923565b8051156105aa5780806020019051611a979190810190611e57565b6105aa5760405162461bcd60e51b81526004016104c1906129e3565b60008183611ad45760405162461bcd60e51b81526004016104c19190612892565b506000838581611ae057fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611787575050151592915050565b828054828255906000526020600020908101928215611b5e579160200282015b82811115611b5e578251825591602001919060010190611b43565b50611b6a929150611b9a565b5090565b815481835581811115611827576004028160040283600052602060002091820191016118279190611bb4565b61049491905b80821115611b6a5760008155600101611ba0565b61049491905b80821115611b6a57600080825560018201819055600282018190556003820155600401611bba565b8035610bfb81612bb3565b60008083601f840112611bff57600080fd5b50813567ffffffffffffffff811115611c1757600080fd5b602083019150836020820283011115611c2f57600080fd5b9250929050565b8035610bfb81612bc7565b8051610bfb81612bc7565b8035610bfb81612bd0565b8051610bfb81612bd0565b8035610bfb81612bd9565b600060208284031215611c7f57600080fd5b60006117878484611be2565b600080600080600060608688031215611ca357600080fd5b6000611caf8888611be2565b955050602086013567ffffffffffffffff811115611ccc57600080fd5b611cd888828901611bed565b9450945050604086013567ffffffffffffffff811115611cf757600080fd5b611d0388828901611bed565b92509250509295509295909350565b60008060408385031215611d2557600080fd5b6000611d318585611be2565b9250506020611d4285828601611c4c565b9150509250929050565b600080600060608486031215611d6157600080fd5b6000611d6d8686611be2565b9350506020611d7e86828701611c4c565b9250506040611d8f86828701611c4c565b9150509250925092565b60008060408385031215611dac57600080fd5b6000611db88585611be2565b9250506020611d4285828601611c62565b60008060008060408587031215611ddf57600080fd5b843567ffffffffffffffff811115611df657600080fd5b611e0287828801611bed565b9450945050602085013567ffffffffffffffff811115611e2157600080fd5b611e2d87828801611bed565b95989497509550505050565b600060208284031215611e4b57600080fd5b60006117878484611c36565b600060208284031215611e6957600080fd5b60006117878484611c41565b600060208284031215611e8757600080fd5b60006117878484611c4c565b600060208284031215611ea557600080fd5b60006117878484611c57565b60008060408385031215611ec457600080fd5b6000611d318585611c4c565b600080600080600080600060c0888a031215611eeb57600080fd5b6000611ef78a8a611c4c565b9750506020611f088a828b01611c62565b9650506040611f198a828b01611c4c565b9550506060611f2a8a828b01611c4c565b9450506080611f3b8a828b01611c4c565b93505060a088013567ffffffffffffffff811115611f5857600080fd5b611f648a828b01611bed565b925092505092959891949750929550565b600060208284031215611f8757600080fd5b60006117878484611c62565b600080600060608486031215611fa857600080fd5b6000611d6d8686611c62565b6000611fc0838361269b565b505060c00190565b6000611fd48383612101565b505060200190565b611fed611fe882612af7565b612b75565b82525050565b611fed81612af7565b600061200782612ae0565b6120118185612aee565b935061201c83612ace565b8060005b8381101561204a5781516120348882611fb4565b975061203f83612ace565b925050600101612020565b509495945050505050565b600061206082612ae0565b61206a8185612aee565b935061207583612ace565b8060005b8381101561204a57815161208d8882611fc8565b975061209883612ace565b925050600101612079565b60006120ae82612ae4565b6120b88185612aee565b93506120c383612ad4565b8060005b8381101561204a576120d882612b91565b6120e28882611fc8565b97506120ed83612ae8565b9250506001016120c7565b611fed81612b02565b611fed81610494565b611fed61211682610494565b610494565b600061212682612ae0565b6121308185610482565b9350612140818560208601612b3b565b9290920192915050565b611fed81612b25565b600061215e82612ae0565b6121688185612aee565b9350612178818560208601612b3b565b61218181612b9d565b9093019392505050565b6000612198600a83612aee565b694d6178207374616b657360b01b815260200192915050565b60006121be601883612aee565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121f7601083612aee565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612223600e83612aee565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061224d601b83612aee565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612286601a83612aee565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122bf600d83612aee565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122e8602683612aee565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612330602083612aee565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612369601183612aee565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612396601c83612aee565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123cf601a83612aee565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b6000612408600e83612aee565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612432601583612aee565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612463602183612aee565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006124a6600e83612aee565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124d0600e83612aee565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124fa602e83612aee565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061254a601483612aee565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061257a600d83612aee565b6c24b73b30b634b210383937b7b360991b815260200192915050565b60006125a3602a83612aee565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125ef601283612aee565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b600061261d603083612aee565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b600061266f601f83612aee565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c08301906126ac8482612101565b5060208201516126bf6020850182612101565b5060408201516126d26040850182612101565b5060608201516126e5606085018261270b565b5060808201516126f860808501826120f8565b5060a08201516105aa60a085018261271d565b611fed81612b13565b611fed81612b30565b611fed81612b1f565b611fed61273282612b1f565b612b86565b6000612743828561210a565b602082019150612753828461210a565b5060200192915050565b6000610963828461211b565b6000612775828a61210a565b6020820191506127858289612726565b6001820191506127958288611fdc565b6014820191506127a58287611fdc565b6014820191506127b5828661210a565b6020820191506127c5828561210a565b6020820191506127d5828461210a565b50602001979650505050505050565b60208101610bfb8284611ff3565b606081016128008286611ff3565b61280d6020830185611ff3565b6117876040830184612101565b604081016128288285611ff3565b6109636020830184612101565b60208082528101610bf88184611ffc565b60208082528101610bf88184612055565b60208082528101610bf881846120a3565b60208101610bfb82846120f8565b604081016128288285612101565b60208101610bfb828461214a565b60208082528101610bf88184612153565b60208082528101610bfb8161218b565b60208082528101610bfb816121b1565b60208082528101610bfb816121ea565b60208082528101610bfb81612216565b60208082528101610bfb81612240565b60208082528101610bfb81612279565b60208082528101610bfb816122b2565b60208082528101610bfb816122db565b60208082528101610bfb81612323565b60208082528101610bfb8161235c565b60208082528101610bfb81612389565b60208082528101610bfb816123c2565b60208082528101610bfb816123fb565b60208082528101610bfb81612425565b60208082528101610bfb81612456565b60208082528101610bfb81612499565b60208082528101610bfb816124c3565b60208082528101610bfb816124ed565b60208082528101610bfb8161253d565b60208082528101610bfb8161256d565b60208082528101610bfb81612596565b60208082528101610bfb816125e2565b60208082528101610bfb81612610565b60208082528101610bfb81612662565b60208101610bfb8284612101565b60608101612a3f8286612101565b612a4c6020830185612101565b6117876040830184612714565b60c08101612a678289612101565b612a746020830188612101565b612a816040830187612101565b612a8e606083018661270b565b612a9b60808301856120f8565b612aa860a083018461271d565b979650505050505050565b60608101612ac1828661271d565b61280d6020830185612101565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612b07565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612af7565b6000610bfb82612b13565b60005b83811015612b56578181015183820152602001612b3e565b838111156105aa5750506000910152565b6000610bfb61211683610494565b6000610bfb826000610bfb82612bad565b6000610bfb82612ba7565b6000610bfb8254612b67565b601f01601f191690565b60f81b90565b60601b90565b612bbc81612af7565b81146115ea57600080fd5b612bbc81612b02565b612bbc81610494565b612bbc81612b1f56fea365627a7a723158200dfb3e06c3cb37079851ef4ebb60b603ca03e591e2736b87fa908d68d042d6576c6578706572696d656e74616cf564736f6c634300050b0040", "devdoc": { "methods": { "airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])": { diff --git a/contracts/deployments/mainnet/solcInputs/c7459e40fa663addef2a13f82ab72194.json b/contracts/deployments/mainnet/solcInputs/c7459e40fa663addef2a13f82ab72194.json new file mode 100644 index 0000000000..8f9bd9516c --- /dev/null +++ b/contracts/deployments/mainnet/solcInputs/c7459e40fa663addef2a13f82ab72194.json @@ -0,0 +1,287 @@ +{ + "language": "Solidity", + "sources": { + "contracts/compensation/CompensationClaims.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) public onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/upgrades/contracts/Initializable.sol": { + "content": "pragma solidity >=0.4.24 <0.7.0;\n\n\n/**\n * @title Initializable\n *\n * @dev Helper contract to support initializer functions. To use it, replace\n * the constructor with a function that has the `initializer` modifier.\n * WARNING: Unlike constructors, initializer functions must be manually\n * invoked. This applies both to deploying an Initializable contract, as well\n * as extending an Initializable contract via inheritance.\n * WARNING: When used with inheritance, manual care must be taken to not invoke\n * a parent initializer twice, or ensure that all initializers are idempotent,\n * because this is not dealt with automatically as with constructors.\n */\ncontract Initializable {\n\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to use in the initializer function of a contract.\n */\n modifier initializer() {\n require(initializing || isConstructor() || !initialized, \"Contract instance has already been initialized\");\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n /// @dev Returns true if and only if the function is running in the constructor\n function isConstructor() private view returns (bool) {\n // extcodesize checks the size of the code stored in an address, and\n // address returns the current address. Since the code is still not\n // deployed when running a constructor, any checks on its code size will\n // yield zero, making it an effective way to detect if a contract is\n // under construction or not.\n address self = address(this);\n uint256 cs;\n assembly { cs := extcodesize(self) }\n return cs == 0;\n }\n\n // Reserved storage space to allow for layout changes in the future.\n uint256[50] private ______gap;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/SafeERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require((value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) { // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/math/SafeMath.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Governable Contract\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\ncontract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @dev Initializes the contract setting the deployer as the initial Governor.\n */\n constructor() internal {\n _setGovernor(msg.sender);\n emit GovernorshipTransferred(address(0), _governor());\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n bytes32 position = governorPosition;\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n emit GovernorshipTransferred(_governor(), _newGovernor);\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "pragma solidity ^0.5.5;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following \n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly { codehash := extcodehash(account) }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(address recipient, uint256 amount);\n\n // Core address for the given platform\n address public platformAddress;\n\n address public vaultAddress;\n\n // asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n // Full list of all assets supported here\n address[] internal assetsMapped;\n\n // Reward token address\n address public rewardTokenAddress;\n uint256 public rewardLiquidationThreshold;\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _platformAddress jGeneric platform address\n * @param _vaultAddress Address of the Vault\n * @param _rewardTokenAddress Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Collect accumulated reward token (COMP) and send to Vault.\n */\n function collectRewardToken() external onlyVault nonReentrant {\n IERC20 rewardToken = IERC20(rewardTokenAddress);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, balance);\n rewardToken.safeTransfer(vaultAddress, balance);\n }\n\n function _initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n platformAddress = _platformAddress;\n vaultAddress = _vaultAddress;\n rewardTokenAddress = _rewardTokenAddress;\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; i++) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @dev Single asset variant of the internal initialize.\n */\n function _initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address _asset,\n address _pToken\n ) internal {\n platformAddress = _platformAddress;\n vaultAddress = _vaultAddress;\n rewardTokenAddress = _rewardTokenAddress;\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Set the reward token address.\n * @param _rewardTokenAddress Address of the reward token\n */\n function setRewardTokenAddress(address _rewardTokenAddress)\n external\n onlyGovernor\n {\n rewardTokenAddress = _rewardTokenAddress;\n }\n\n /**\n * @dev Set the reward token liquidation threshold.\n * @param _threshold Threshold amount in decimals of reward token that will\n * cause the Vault to claim and withdrawAll on allocate() calls.\n */\n function setRewardLiquidationThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n rewardLiquidationThreshold = _threshold;\n }\n\n /**\n * @dev Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @dev Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @dev Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken) internal;\n\n function safeApproveAllTokens() external;\n\n /**\n * @dev Deposit a amount of asset into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Withdraw an amount of asset from the platform.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Withdraw all assets from strategy sending assets to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) external view returns (bool);\n}\n" + }, + "contracts/strategies/ThreePoolStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICurveGauge } from \"./ICurveGauge.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\ncontract ThreePoolStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n\n event RewardTokenCollected(address recipient, uint256 amount);\n\n address crvGaugeAddress;\n address crvMinterAddress;\n int128 poolCoinIndex = -1;\n uint256 constant maxSlippage = 1e16; // 1%, same as the Curve UI\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _platformAddress Address of the Curve 3pool\n * @param _vaultAddress Address of the vault\n * @param _rewardTokenAddress Address of CRV\n * @param _asset Address of the supported asset\n * @param _pToken Correspond platform token addres (i.e. 3Crv)\n * @param _crvGaugeAddress Address of the Curve DAO gauge for this pool\n * @param _crvMinterAddress Address of the CRV minter for rewards\n */\n function initialize(\n address _platformAddress, // 3Pool address\n address _vaultAddress,\n address _rewardTokenAddress, // CRV\n address _asset,\n address _pToken,\n address _crvGaugeAddress,\n address _crvMinterAddress\n ) external onlyGovernor initializer {\n ICurvePool threePool = ICurvePool(_platformAddress);\n for (int128 i = 0; i < 3; i++) {\n if (threePool.coins(uint256(i)) == _asset) poolCoinIndex = i;\n }\n require(poolCoinIndex != -1, \"Invalid 3pool asset\");\n crvGaugeAddress = _crvGaugeAddress;\n crvMinterAddress = _crvMinterAddress;\n InitializableAbstractStrategy._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _asset,\n _pToken\n );\n }\n\n /**\n * @dev Collect accumulated CRV and send to Vault.\n */\n function collectRewardToken() external onlyVault nonReentrant {\n IERC20 crvToken = IERC20(rewardTokenAddress);\n ICRVMinter minter = ICRVMinter(crvMinterAddress);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, balance);\n minter.mint(crvGaugeAddress);\n crvToken.safeTransfer(vaultAddress, balance);\n }\n\n /**\n * @dev Deposit asset into the Curve 3Pool\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, address(platformAddress), _amount);\n // 3Pool requires passing deposit amounts for all 3 assets, set to 0 for\n // all\n uint256[3] memory _amounts;\n // Set the amount on the asset we want to deposit\n _amounts[uint256(poolCoinIndex)] = _amount;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 depositValue = _amount\n .scaleBy(int8(18 - assetDecimals))\n .divPrecisely(curvePool.get_virtual_price());\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n // Deposit into Gauge\n IERC20 pToken = IERC20(assetToPToken[_asset]);\n ICurveGauge(crvGaugeAddress).deposit(\n pToken.balanceOf(address(this)),\n address(this)\n );\n }\n\n /**\n * @dev Withdraw asset from Curve 3Pool\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_recipient != address(0), \"Invalid recipient\");\n require(_amount > 0, \"Invalid amount\");\n\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\n\n // Calculate how much of the pool token we need to withdraw\n (uint256 contractPTokens, , uint256 totalPTokens) = _getTotalPTokens();\n // Calculate the max amount of the asset we'd get if we withdrew all the\n // platform tokens\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 maxAmount = curvePool.calc_withdraw_one_coin(\n totalPTokens,\n poolCoinIndex\n );\n // Calculate how many platform tokens we need to withdraw the asset amount\n uint256 withdrawPTokens = totalPTokens.mul(_amount).div(maxAmount);\n if (contractPTokens < withdrawPTokens) {\n // Not enough of pool token exists on this contract, must be staked\n // in Gauge, unstake\n ICurveGauge(crvGaugeAddress).withdraw(withdrawPTokens);\n }\n uint256 minWithdrawAmount = withdrawPTokens.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n curvePool.remove_liquidity_one_coin(\n withdrawPTokens,\n poolCoinIndex,\n minWithdrawAmount\n );\n IERC20(_asset).safeTransfer(_recipient, _amount);\n // Transfer any leftover dust back to the vault buffer.\n uint256 dust = IERC20(_asset).balanceOf(address(this));\n if (dust > 0) {\n IERC20(_asset).safeTransfer(vaultAddress, dust);\n }\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n // Withdraw all from Gauge\n (, uint256 gaugePTokens, ) = _getTotalPTokens();\n ICurveGauge(crvGaugeAddress).withdraw(gaugePTokens);\n // Remove entire balance, 3pool strategies only support a single asset\n // so safe to use assetsMapped[0]\n IERC20 asset = IERC20(assetsMapped[0]);\n uint256 pTokenBalance = IERC20(assetToPToken[address(asset)]).balanceOf(\n address(this)\n );\n uint256 minWithdrawAmount = pTokenBalance.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n ICurvePool(platformAddress).remove_liquidity_one_coin(\n pTokenBalance,\n poolCoinIndex,\n minWithdrawAmount\n );\n // Transfer the asset out to Vault\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * This includes any interest that was generated since depositing\n * We calculate this by calculating a what we would get if we withdrawAlld\n * the allocated percentage of this asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n (, , uint256 totalPTokens) = _getTotalPTokens();\n balance = 0;\n if (totalPTokens > 0) {\n balance += ICurvePool(platformAddress).calc_withdraw_one_coin(\n totalPTokens,\n poolCoinIndex\n );\n }\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external {\n // This strategy is a special case since it only supports one asset\n address assetAddress = assetsMapped[0];\n _abstractSetPToken(assetAddress, assetToPToken[assetAddress]);\n }\n\n /**\n * @dev Calculate the total platform token balance (i.e. 3CRV) that exist in\n * this contract or is staked in the Gauge (or in other words, the total\n * amount platform tokens we own).\n * @return totalPTokens Total amount of platform tokens in native decimals\n */\n function _getTotalPTokens()\n internal\n view\n returns (\n uint256 contractPTokens,\n uint256 gaugePTokens,\n uint256 totalPTokens\n )\n {\n contractPTokens = IERC20(assetToPToken[assetsMapped[0]]).balanceOf(\n address(this)\n );\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n gaugePTokens = gauge.balanceOf(address(this));\n totalPTokens = contractPTokens.add(gaugePTokens);\n }\n\n /**\n * @dev Call the necessary approvals for the Curve pool and gauge\n * @param _asset Address of the asset\n * @param _pToken Address of the corresponding platform token (i.e. 3CRV)\n */\n function _abstractSetPToken(address _asset, address _pToken) internal {\n IERC20 asset = IERC20(_asset);\n IERC20 pToken = IERC20(_pToken);\n // 3Pool for asset (required for adding liquidity)\n asset.safeApprove(platformAddress, 0);\n asset.safeApprove(platformAddress, uint256(-1));\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, uint256(-1));\n // Gauge for LP token\n pToken.safeApprove(crvGaugeAddress, 0);\n pToken.safeApprove(crvGaugeAddress, uint256(-1));\n }\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICurvePool {\n function get_virtual_price() external returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n}\n" + }, + "contracts/strategies/ICurveGauge.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICurveGauge {\n function balanceOf(address account) external view returns (uint256);\n\n function deposit(uint256 value, address account) external;\n\n function withdraw(uint256 value) external;\n}\n" + }, + "contracts/strategies/ICRVMinter.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICRVMinter {\n function mint(address gaugeAddress) external;\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\n */\n function scaleBy(uint256 x, int8 adjustment)\n internal\n pure\n returns (uint256)\n {\n if (adjustment > 0) {\n x = x.mul(10**uint256(adjustment));\n } else if (adjustment < 0) {\n x = x.div(10**uint256(adjustment * -1));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e38 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultStorage Contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract VaultStorage is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeMath for int256;\n using SafeERC20 for IERC20;\n\n event AssetSupported(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event UniswapUpdated(address _address);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n\n // Assets supported by the Vault, i.e. Stablecoins\n struct Asset {\n bool isSupported;\n }\n mapping(address => Asset) assets;\n address[] allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n mapping(address => Strategy) strategies;\n address[] allStrategies;\n\n // Address of the Oracle price provider contract\n address public priceProvider;\n // Pausing bools\n bool public rebasePaused = false;\n bool public capitalPaused = true;\n // Redemption fee in basis points\n uint256 public redeemFeeBps;\n // Buffer of assets to keep in Vault to handle (most) withdrawals\n uint256 public vaultBuffer;\n // Mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n // Mints over this amount automatically rebase. 18 decimals.\n uint256 public rebaseThreshold;\n\n OUSD oUSD;\n\n //keccak256(\"OUSD.vault.governor.admin.impl\");\n bytes32 constant adminImplPosition = 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\n\n // Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n // Address of Uniswap\n address public uniswapAddr = address(0);\n\n // Address of the Strategist\n address public strategistAddr = address(0);\n\n // Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n mapping(address => address) public assetDefaultStrategies;\n\n uint256 public maxSupplyDiff;\n\n /**\n * @dev set the implementation for the admin, this needs to be in a base class else we cannot set it\n * @param newImpl address of the implementation\n */\n function setAdminImpl(address newImpl) external onlyGovernor {\n require(\n Address.isContract(newImpl),\n \"new implementation is not a contract\"\n );\n bytes32 position = adminImplPosition;\n assembly {\n sstore(position, newImpl)\n }\n }\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to Lending platform.\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardToken() external;\n\n /**\n * @dev The address of the reward token for the Strategy.\n */\n function rewardTokenAddress() external pure returns (address);\n\n /**\n * @dev The threshold (denominated in the reward token) over which the\n * vault will auto harvest on allocate calls.\n */\n function rewardLiquidationThreshold() external pure returns (uint256);\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport {\n InitializableERC20Detailed\n} from \"../utils/InitializableERC20Detailed.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * NOTE that this is an ERC20 token but the invariant that the sum of\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\n * rebasing design. Any integrations with OUSD should be aware.\n */\n\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n\n event TotalSupplyUpdated(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n\n enum RebaseOptions { NotSet, OptOut, OptIn }\n\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\n uint256 public _totalSupply;\n mapping(address => mapping(address => uint256)) private _allowances;\n address public vaultAddress = address(0);\n mapping(address => uint256) private _creditBalances;\n uint256 public rebasingCredits;\n uint256 public rebasingCreditsPerToken;\n // Frozen address/credits are non rebasing (value is held in contracts which\n // do not receive yield unless they explicitly opt in)\n uint256 public nonRebasingSupply;\n mapping(address => uint256) public nonRebasingCreditsPerToken;\n mapping(address => RebaseOptions) public rebaseState;\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress\n ) external onlyGovernor initializer {\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\n rebasingCreditsPerToken = 1e18;\n vaultAddress = _vaultAddress;\n }\n\n /**\n * @dev Verifies that the caller is the Savings Manager contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return The total supply of OUSD.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the _amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account) public view returns (uint256) {\n if (_creditBalances[_account] == 0) return 0;\n return\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n public\n view\n returns (uint256, uint256)\n {\n return (_creditBalances[_account], _creditsPerToken(_account));\n }\n\n /**\n * @dev Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the _amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(\n _value <= balanceOf(msg.sender),\n \"Transfer greater than balance\"\n );\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The _amount of tokens to be transferred.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(_value <= balanceOf(_from), \"Transfer greater than balance\");\n\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\n _value\n );\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Update the count of non rebasing credits in response to a transfer\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value Amount of OUSD to transfer\n */\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\n\n // Credits deducted and credited might be different due to the\n // differing creditsPerToken used by each account\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\n\n _creditBalances[_from] = _creditBalances[_from].sub(\n creditsDeducted,\n \"Transfer amount exceeds balance\"\n );\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\n\n if (isNonRebasingTo && !isNonRebasingFrom) {\n // Transfer to non-rebasing account from rebasing account, credits\n // are removed from the non rebasing tally\n nonRebasingSupply = nonRebasingSupply.add(_value);\n // Update rebasingCredits by subtracting the deducted amount\n rebasingCredits = rebasingCredits.sub(creditsDeducted);\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\n // Transfer to rebasing account from non-rebasing account\n // Decreasing non-rebasing credits by the amount that was sent\n nonRebasingSupply = nonRebasingSupply.sub(_value);\n // Update rebasingCredits by adding the credited amount\n rebasingCredits = rebasingCredits.add(creditsCredited);\n }\n }\n\n /**\n * @dev Function to check the _amount of tokens that an owner has allowed to a _spender.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n public\n view\n returns (uint256)\n {\n return _allowances[_owner][_spender];\n }\n\n /**\n * @dev Approve the passed address to spend the specified _amount of tokens on behalf of\n * msg.sender. This method is included for ERC20 compatibility.\n * increaseAllowance and decreaseAllowance should be used instead.\n * Changing an allowance with this method brings the risk that someone may transfer both\n * the old and the new allowance - if they are both greater than zero - if a transfer\n * transaction is mined before the later approve() call is mined.\n *\n * @param _spender The address which will spend the funds.\n * @param _value The _amount of tokens to be spent.\n */\n function approve(address _spender, uint256 _value) public returns (bool) {\n _allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @dev Increase the _amount of tokens that an owner has allowed to a _spender.\n * This method should be used instead of approve() to avoid the double approval vulnerability\n * described above.\n * @param _spender The address which will spend the funds.\n * @param _addedValue The _amount of tokens to increase the allowance by.\n */\n function increaseAllowance(address _spender, uint256 _addedValue)\n public\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\n .add(_addedValue);\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Decrease the _amount of tokens that an owner has allowed to a _spender.\n * @param _spender The address which will spend the funds.\n * @param _subtractedValue The _amount of tokens to decrease the allowance by.\n */\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n public\n returns (bool)\n {\n uint256 oldValue = _allowances[msg.sender][_spender];\n if (_subtractedValue >= oldValue) {\n _allowances[msg.sender][_spender] = 0;\n } else {\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\n }\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Mints new tokens, increasing totalSupply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n return _mint(_account, _amount);\n }\n\n /**\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Mint to the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\n\n // If the account is non rebasing and doesn't have a set creditsPerToken\n // then set it i.e. this is a mint from a fresh contract\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.add(_amount);\n } else {\n rebasingCredits = rebasingCredits.add(creditAmount);\n }\n\n _totalSupply = _totalSupply.add(_amount);\n\n require(_totalSupply < MAX_SUPPLY, \"Max supply\");\n\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @dev Burns tokens, decreasing totalSupply.\n */\n function burn(address account, uint256 amount) external onlyVault {\n return _burn(account, amount);\n }\n\n /**\n * @dev Destroys `_amount` tokens from `_account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `_account` cannot be the zero address.\n * - `_account` must have at least `_amount` tokens.\n */\n function _burn(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Burn from the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n uint256 currentCredits = _creditBalances[_account];\n\n // Remove the credits, burning rounding errors\n if (\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\n ) {\n // Handle dust from rounding\n _creditBalances[_account] = 0;\n } else if (currentCredits > creditAmount) {\n _creditBalances[_account] = _creditBalances[_account].sub(\n creditAmount\n );\n } else {\n revert(\"Remove exceeds balance\");\n }\n\n // Remove from the credit tallies and non-rebasing supply\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\n } else {\n rebasingCredits = rebasingCredits.sub(creditAmount);\n }\n\n _totalSupply = _totalSupply.sub(_amount);\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n if (nonRebasingCreditsPerToken[_account] != 0) {\n return nonRebasingCreditsPerToken[_account];\n } else {\n return rebasingCreditsPerToken;\n }\n }\n\n /**\n * @dev Is an accounts balance non rebasing, i.e. does not alter with rebases\n * @param _account Address of the account.\n */\n function _isNonRebasingAccount(address _account) internal returns (bool) {\n if (Address.isContract(_account)) {\n // Contracts by default opt out\n if (rebaseState[_account] == RebaseOptions.OptIn) {\n // If they've opted in explicitly it is not a non rebasing\n // address\n return false;\n }\n // Is a non rebasing account because no explicit opt in\n // Make sure the rebasing/non-rebasing supply is updated and\n // fixed credits per token is set for this account\n _ensureRebasingMigration(_account);\n return true;\n } else {\n // EOAs by default opt in\n // Check for explicit opt out\n return rebaseState[_account] == RebaseOptions.OptOut;\n }\n }\n\n /**\n * @dev Ensures internal account for rebasing and non-rebasing credits and\n * supply is updated following deployment of frozen yield change.\n */\n function _ensureRebasingMigration(address _account) internal {\n if (nonRebasingCreditsPerToken[_account] == 0) {\n // Set fixed credits per token for this account\n nonRebasingCreditsPerToken[_account] = rebasingCreditsPerToken;\n // Update non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\n // Update credit tallies\n rebasingCredits = rebasingCredits.sub(_creditBalances[_account]);\n }\n }\n\n /**\n * @dev Add a contract address to the non rebasing exception list. I.e. the\n * address's balance will be part of rebases so the account will be exposed\n * to upside and downside.\n */\n function rebaseOptIn() public nonReentrant {\n require(_isNonRebasingAccount(msg.sender), \"Account has not opted out\");\n\n // Convert balance into the same amount at the current exchange rate\n uint256 newCreditBalance = _creditBalances[msg.sender]\n .mul(rebasingCreditsPerToken)\n .div(_creditsPerToken(msg.sender));\n\n // Decreasing non rebasing supply\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender));\n\n _creditBalances[msg.sender] = newCreditBalance;\n\n // Increase rebasing credits, totalSupply remains unchanged so no\n // adjustment necessary\n rebasingCredits = rebasingCredits.add(_creditBalances[msg.sender]);\n\n rebaseState[msg.sender] = RebaseOptions.OptIn;\n\n // Delete any fixed credits per token\n delete nonRebasingCreditsPerToken[msg.sender];\n }\n\n /**\n * @dev Remove a contract address to the non rebasing exception list.\n */\n function rebaseOptOut() public nonReentrant {\n require(!_isNonRebasingAccount(msg.sender), \"Account has not opted in\");\n\n // Increase non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\n // Set fixed credits per token\n nonRebasingCreditsPerToken[msg.sender] = rebasingCreditsPerToken;\n\n // Decrease rebasing credits, total supply remains unchanged so no\n // adjustment necessary\n rebasingCredits = rebasingCredits.sub(_creditBalances[msg.sender]);\n\n // Mark explicitly opted out of rebasing\n rebaseState[msg.sender] = RebaseOptions.OptOut;\n }\n\n /**\n * @dev Modify the supply without minting new tokens. This uses a change in\n * the exchange rate between \"credits\" and OUSD tokens to change balances.\n * @param _newTotalSupply New total supply of OUSD.\n * @return uint256 representing the new total supply.\n */\n function changeSupply(uint256 _newTotalSupply)\n external\n onlyVault\n nonReentrant\n {\n require(_totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (_totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdated(\n _totalSupply,\n rebasingCredits,\n rebasingCreditsPerToken\n );\n return;\n }\n\n _totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n rebasingCreditsPerToken = rebasingCredits.divPrecisely(\n _totalSupply.sub(nonRebasingSupply)\n );\n\n require(rebasingCreditsPerToken > 0, \"Invalid change in supply\");\n\n _totalSupply = rebasingCredits\n .divPrecisely(rebasingCreditsPerToken)\n .add(nonRebasingSupply);\n\n emit TotalSupplyUpdated(\n _totalSupply,\n rebasingCredits,\n rebasingCreditsPerToken\n );\n }\n}\n" + }, + "contracts/utils/InitializableERC20Detailed.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\n */\ncontract InitializableERC20Detailed is IERC20 {\n // Storage gap to skip storage from prior to OUSD reset\n uint256[100] private _____gap;\n\n string public _name;\n string public _symbol;\n uint8 public _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\n */\n function _initialize(\n string memory nameArg,\n string memory symbolArg,\n uint8 decimalsArg\n ) internal {\n _name = nameArg;\n _symbol = symbolArg;\n _decimals = decimalsArg;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Vault Admin Contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\n\ncontract VaultAdmin is VaultStorage {\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == address(this) || isGovernor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * @dev Set address of price provider.\n * @param _priceProvider Address of price provider\n */\n function setPriceProvider(address _priceProvider) external onlyGovernor {\n priceProvider = _priceProvider;\n emit PriceProviderUpdated(_priceProvider);\n }\n\n /**\n * @dev Set a fee in basis points to be charged for a redeem.\n * @param _redeemFeeBps Basis point fee to be charged\n */\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\n redeemFeeBps = _redeemFeeBps;\n emit RedeemFeeUpdated(_redeemFeeBps);\n }\n\n /**\n * @dev Set a buffer of assets to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding assets from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer) external onlyGovernor {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @dev Sets the minimum amount of OUSD in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OUSD amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @dev Set a minimum amount of OUSD in a mint or redeem that triggers a\n * rebase\n * @param _threshold OUSD amount with 18 fixed decimals.\n */\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\n rebaseThreshold = _threshold;\n emit RebaseThresholdUpdated(_threshold);\n }\n\n /**\n * @dev Set address of Uniswap for performing liquidation of strategy reward\n * tokens\n * @param _address Address of Uniswap\n */\n function setUniswapAddr(address _address) external onlyGovernor {\n uniswapAddr = _address;\n emit UniswapUpdated(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @dev Set the default Strategy for an asset, i.e. the one which the asset\n will be automatically allocated to and withdrawn from\n * @param _asset Address of the asset\n * @param _strategy Address of the Strategy\n */\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n IStrategy strategy = IStrategy(_strategy);\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(\n strategy.supportsAsset(_asset),\n \"Asset not supported by Strategy\"\n );\n assetDefaultStrategies[_asset] = _strategy;\n }\n\n /**\n * @dev Add a supported asset to the contract, i.e. one that can be\n * to mint OUSD.\n * @param _asset Address of asset\n */\n function supportAsset(address _asset) external onlyGovernor {\n require(!assets[_asset].isSupported, \"Asset already supported\");\n\n assets[_asset] = Asset({ isSupported: true });\n allAssets.push(_asset);\n\n emit AssetSupported(_asset);\n }\n\n /**\n * @dev Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @dev Remove a strategy from the Vault. Removes all invested assets and\n * returns them to the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 strategyIndex = allStrategies.length;\n for (uint256 i = 0; i < allStrategies.length; i++) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < allStrategies.length) {\n allStrategies[strategyIndex] = allStrategies[allStrategies.length -\n 1];\n allStrategies.pop();\n\n // Withdraw all assets\n IStrategy strategy = IStrategy(_addr);\n strategy.withdrawAll();\n // Call harvest after withdraw in case withdraw triggers\n // distribution of additional reward tokens (true for Compound)\n _harvest(_addr);\n emit StrategyRemoved(_addr);\n }\n\n // Clean up struct in mapping, this can be removed later\n // See https://github.com/OriginProtocol/origin-dollar/issues/324\n strategies[_addr].isSupported = false;\n }\n\n /**\n * @notice Move assets from one Strategy to another\n * @param _strategyFromAddress Address of Strategy to move assets from.\n * @param _strategyToAddress Address of Strategy to move assets to.\n * @param _assets Array of asset address that will be moved\n * @param _amounts Array of amounts of each corresponding asset to move.\n */\n function reallocate(\n address _strategyFromAddress,\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n IStrategy strategyFrom = IStrategy(_strategyFromAddress);\n IStrategy strategyTo = IStrategy(_strategyToAddress);\n\n for (uint256 i = 0; i < _assets.length; i++) {\n require(strategyTo.supportsAsset(_assets[i]), \"Asset unsupported\");\n // Withdraw from Strategy and pass other Strategy as recipient\n strategyFrom.withdraw(address(strategyTo), _assets[i], _amounts[i]);\n // Tell new Strategy to deposit into protocol\n strategyTo.deposit(_assets[i], _amounts[i]);\n }\n }\n\n /**\n * @dev Sets the maximum allowable difference between\n * total supply and backing assets' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @dev Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernor {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @dev Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernor {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @dev Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @dev Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from all strategies and swap for supported\n * stablecoin via Uniswap\n */\n function harvest() external onlyGovernor {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n _harvest(allStrategies[i]);\n }\n }\n\n /**\n * @dev Collect reward tokens for a specific strategy and swap for supported\n * stablecoin via Uniswap\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvest(address _strategyAddr)\n external\n onlyVaultOrGovernor\n returns (uint256[] memory)\n {\n return _harvest(_strategyAddr);\n }\n\n /**\n * @dev Collect reward tokens from a single strategy and swap them for a\n * supported stablecoin via Uniswap\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function _harvest(address _strategyAddr)\n internal\n returns (uint256[] memory)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n address rewardTokenAddress = strategy.rewardTokenAddress();\n if (rewardTokenAddress != address(0)) {\n strategy.collectRewardToken();\n\n if (uniswapAddr != address(0)) {\n IERC20 rewardToken = IERC20(strategy.rewardTokenAddress());\n uint256 rewardTokenAmount = rewardToken.balanceOf(\n address(this)\n );\n if (rewardTokenAmount > 0) {\n // Give Uniswap full amount allowance\n rewardToken.safeApprove(uniswapAddr, 0);\n rewardToken.safeApprove(uniswapAddr, rewardTokenAmount);\n\n // Uniswap redemption path\n address[] memory path = new address[](3);\n path[0] = strategy.rewardTokenAddress();\n path[1] = IUniswapV2Router(uniswapAddr).WETH();\n path[2] = allAssets[1]; // USDT\n\n return\n IUniswapV2Router(uniswapAddr).swapExactTokensForTokens(\n rewardTokenAmount,\n uint256(0),\n path,\n address(this),\n now.add(1800)\n );\n }\n }\n }\n }\n\n /***************************************\n Pricing\n ****************************************/\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Min since min is what we use for mint pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function priceUSDMint(string calldata symbol)\n external\n view\n returns (uint256)\n {\n return _priceUSDMint(symbol);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Min since min is what we use for mint pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function _priceUSDMint(string memory symbol)\n internal\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return IMinMaxOracle(priceProvider).priceMin(symbol).scaleBy(10);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Max since max is what we use for redeem pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function priceUSDRedeem(string calldata symbol)\n external\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return _priceUSDRedeem(symbol);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Max since max is what we use for redeem pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function _priceUSDRedeem(string memory symbol)\n internal\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return IMinMaxOracle(priceProvider).priceMax(symbol).scaleBy(10);\n }\n}\n" + }, + "contracts/interfaces/IMinMaxOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n address tok0;\n address tok1;\n\n address public WETH = address(0);\n\n function initialize(address _token0, address _token1) public {\n tok0 = _token0;\n tok1 = _token1;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts) {\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n IERC20(tok1).transfer(\n to,\n amountIn.scaleBy(\n int8(Helpers.getDecimals(tok1) - Helpers.getDecimals(tok0))\n )\n );\n }\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "pragma solidity 0.5.11;\npragma experimental ABIEncoderV2;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < uint240(-1), \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.length += 1; // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < uint240(-1), \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n IAaveAToken,\n IAaveLendingPool,\n ILendingPoolAddressesProvider\n} from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport {\n IERC20,\n ERC20,\n ERC20Mintable\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport {\n ERC20Detailed\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is ERC20Mintable, ERC20Detailed {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n )\n public\n ERC20Detailed(\n _name,\n _symbol,\n ERC20Detailed(address(_underlyingToken)).decimals()\n )\n {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n addMinter(_lendingPool);\n }\n\n function redeem(uint256 _amount) external {\n // Redeem these a Tokens\n _burn(msg.sender, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, msg.sender, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = address(uint160(address(this)));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, uint256(-1));\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n uint16 /*_referralCode*/\n ) external {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n ERC20Mintable(reserveToAToken[_reserve]).mint(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n ERC20Mintable(reserveToAToken[_reserve]).mint(msg.sender, _amount);\n }\n\n function getLendingPool() external view returns (address) {\n return pool;\n }\n\n function getLendingPoolCore() external view returns (address payable) {\n return core;\n }\n}\n" + }, + "contracts/strategies/IAave.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @dev Interface for Aaves A Token\n * Documentation: https://developers.aave.com/#atokens\n */\ninterface IAaveAToken {\n /**\n * @notice Non-standard ERC20 function to redeem an _amount of aTokens for the underlying\n * asset, burning the aTokens during the process.\n * @param _amount Amount of aTokens\n */\n function redeem(uint256 _amount) external;\n\n /**\n * @notice returns the current total aToken balance of _user all interest collected included.\n * To obtain the user asset principal balance with interests excluded , ERC20 non-standard\n * method principalBalanceOf() can be used.\n */\n function balanceOf(address _user) external view returns (uint256);\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpool\n */\ninterface IAaveLendingPool {\n /**\n * @notice Deposits a certain _amount of an asset specified by the _reserve parameter.\n * @dev The caller receives a certain amount of corresponding aTokens in exchange.\n * The amount of aTokens received depends on the corresponding aToken exchange rate.\n * LendingPoolCore must be approved to spend this reserve\n */\n function deposit(\n address _reserve,\n uint256 _amount,\n uint16 _referralCode\n ) external;\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpooladdressesprovider\n */\ninterface ILendingPoolAddressesProvider {\n /**\n * @notice Get the current address for Aave LendingPool\n * @dev Lending pool is the core contract on which to call deposit\n */\n function getLendingPool() external view returns (address);\n\n /**\n * @notice Get the address for lendingPoolCore\n * @dev IMPORTANT - this is where _reserve must be approved before deposit\n */\n function getLendingPoolCore() external view returns (address payable);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./ERC20.sol\";\nimport \"../../access/roles/MinterRole.sol\";\n\n/**\n * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},\n * which have permission to mint (create) new tokens as they see fit.\n *\n * At construction, the deployer of the contract is the only minter.\n */\ncontract ERC20Mintable is ERC20, MinterRole {\n /**\n * @dev See {ERC20-_mint}.\n *\n * Requirements:\n *\n * - the caller must have the {MinterRole}.\n */\n function mint(address account, uint256 amount) public onlyMinter returns (bool) {\n _mint(account, amount);\n return true;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20 {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor (string memory name, string memory symbol, uint8 decimals) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20 {\n using SafeMath for uint256;\n\n mapping (address => uint256) private _balances;\n\n mapping (address => mapping (address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, \"ERC20: transfer amount exceeds allowance\"));\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, \"ERC20: decreased allowance below zero\"));\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(address sender, address recipient, uint256 amount) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(amount, \"ERC20: transfer amount exceeds balance\");\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\"));\n }\n}\n" + }, + "@openzeppelin/contracts/access/roles/MinterRole.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"../Roles.sol\";\n\ncontract MinterRole is Context {\n using Roles for Roles.Role;\n\n event MinterAdded(address indexed account);\n event MinterRemoved(address indexed account);\n\n Roles.Role private _minters;\n\n constructor () internal {\n _addMinter(_msgSender());\n }\n\n modifier onlyMinter() {\n require(isMinter(_msgSender()), \"MinterRole: caller does not have the Minter role\");\n _;\n }\n\n function isMinter(address account) public view returns (bool) {\n return _minters.has(account);\n }\n\n function addMinter(address account) public onlyMinter {\n _addMinter(account);\n }\n\n function renounceMinter() public {\n _removeMinter(_msgSender());\n }\n\n function _addMinter(address account) internal {\n _minters.add(account);\n emit MinterAdded(account);\n }\n\n function _removeMinter(address account) internal {\n _minters.remove(account);\n emit MinterRemoved(account);\n }\n}\n" + }, + "@openzeppelin/contracts/GSN/Context.sol": { + "content": "pragma solidity ^0.5.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor () internal { }\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/access/Roles.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @title Roles\n * @dev Library for managing addresses assigned to a Role.\n */\nlibrary Roles {\n struct Role {\n mapping (address => bool) bearer;\n }\n\n /**\n * @dev Give an account access to this role.\n */\n function add(Role storage role, address account) internal {\n require(!has(role, account), \"Roles: account already has role\");\n role.bearer[account] = true;\n }\n\n /**\n * @dev Remove an account's access to this role.\n */\n function remove(Role storage role, address account) internal {\n require(has(role, account), \"Roles: account does not have role\");\n role.bearer[account] = false;\n }\n\n /**\n * @dev Check if an account has this role.\n * @return bool\n */\n function has(Role storage role, address account) internal view returns (bool) {\n require(account != address(0), \"Roles: account is the zero address\");\n return role.bearer[account];\n }\n}\n" + }, + "contracts/mocks/MockOGN.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\nimport \"./WhitelistedPausableToken.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting, burning, and pausing by contract owner.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\n// Removed ERC20Mintable since this is a Mock and we're just exposing the mint function directly\ncontract MockOGN is ERC20Burnable, WhitelistedPausableToken, ERC20Detailed {\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply)\n public\n ERC20Detailed(\"OriginToken\", \"OGN\", 18)\n {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n // @dev Helper method for mocks testing to allow tests to quickly fund users\n // @param _value Amount of token to be created\n function mint(uint256 _value) external returns (bool) {\n _mint(msg.sender, _value);\n return true;\n }\n\n //\n // Burn methods\n //\n\n // @dev Burns tokens belonging to the sender\n // @param _value Amount of token to be burned\n function burn(uint256 _value) public onlyOwner {\n // TODO: add a function & modifier to enable for all accounts without doing\n // a contract migration?\n super.burn(_value);\n }\n\n // @dev Burns tokens belonging to the specified address\n // @param _who The account whose tokens we're burning\n // @param _value Amount of token to be burned\n function burn(address _who, uint256 _value) public onlyOwner {\n _burn(_who, _value);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(msg.sender),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call.value(msg.value)(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./ERC20.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\ncontract ERC20Burnable is Context, ERC20 {\n /**\n * @dev Destroys `amount` tokens from the caller.\n *\n * See {ERC20-_burn}.\n */\n function burn(uint256 amount) public {\n _burn(_msgSender(), amount);\n }\n\n /**\n * @dev See {ERC20-_burnFrom}.\n */\n function burnFrom(address account, uint256 amount) public {\n _burnFrom(account, amount);\n }\n}\n" + }, + "contracts/mocks/WhitelistedPausableToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol\";\n\n/**\n * @title Contract for enforcing a list of addresses allowed to send or receive tokens\n * @dev Until the whitelist expiration expires, this contract only permits\n * token transfers in which an allowed transactor is either the sender or\n * recipient. Once the whitelist expiration passes, it becomes impossible to\n * re-enable the whitelist.\n *\n * This contract inherits from ERC20Pausable to enforce both pausing and\n * whitelists for transfer calls.\n */\ncontract WhitelistedPausableToken is ERC20Pausable {\n address public owner = msg.sender;\n\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./ERC20.sol\";\nimport \"../../lifecycle/Pausable.sol\";\n\n/**\n * @title Pausable token\n * @dev ERC20 with pausable transfers and allowances.\n *\n * Useful if you want to stop trades until the end of a crowdsale, or have\n * an emergency switch for freezing all token transfers in the event of a large\n * bug.\n */\ncontract ERC20Pausable is ERC20, Pausable {\n function transfer(address to, uint256 value) public whenNotPaused returns (bool) {\n return super.transfer(to, value);\n }\n\n function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {\n return super.transferFrom(from, to, value);\n }\n\n function approve(address spender, uint256 value) public whenNotPaused returns (bool) {\n return super.approve(spender, value);\n }\n\n function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) {\n return super.increaseAllowance(spender, addedValue);\n }\n\n function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) {\n return super.decreaseAllowance(spender, subtractedValue);\n }\n}\n" + }, + "@openzeppelin/contracts/lifecycle/Pausable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../GSN/Context.sol\";\nimport \"../access/roles/PauserRole.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\ncontract Pausable is Context, PauserRole {\n /**\n * @dev Emitted when the pause is triggered by a pauser (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by a pauser (`account`).\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state. Assigns the Pauser role\n * to the deployer.\n */\n constructor () internal {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by a pauser to pause, triggers stopped state.\n */\n function pause() public onlyPauser whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by a pauser to unpause, returns to normal state.\n */\n function unpause() public onlyPauser whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/access/roles/PauserRole.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"../Roles.sol\";\n\ncontract PauserRole is Context {\n using Roles for Roles.Role;\n\n event PauserAdded(address indexed account);\n event PauserRemoved(address indexed account);\n\n Roles.Role private _pausers;\n\n constructor () internal {\n _addPauser(_msgSender());\n }\n\n modifier onlyPauser() {\n require(isPauser(_msgSender()), \"PauserRole: caller does not have the Pauser role\");\n _;\n }\n\n function isPauser(address account) public view returns (bool) {\n return _pausers.has(account);\n }\n\n function addPauser(address account) public onlyPauser {\n _addPauser(account);\n }\n\n function renouncePauser() public {\n _removePauser(_msgSender());\n }\n\n function _addPauser(address account) internal {\n _pausers.add(account);\n emit PauserAdded(account);\n }\n\n function _removePauser(address account) internal {\n _pausers.remove(account);\n emit PauserRemoved(account);\n }\n}\n" + }, + "contracts/mocks/MockCToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n IERC20,\n ERC20,\n ERC20Mintable\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport {\n ERC20Detailed\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20, ERC20Detailed, ERC20Mintable {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n\n constructor(ERC20Detailed _underlyingToken)\n public\n ERC20Detailed(\"cMock\", \"cMK\", 8)\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n }\n\n function mint(uint256 mintAmount) external returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256) {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner) external returns (uint256) {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function updateExchangeRate() internal returns (uint256) {\n uint256 factor = 100002 * (10**13); // 0.002%\n exchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external view returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/strategies/ICompound.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @dev Compound C Token interface\n * Documentation: https://compound.finance/developers/ctokens\n */\ninterface ICERC20 {\n /**\n * @notice The mint function transfers an asset into the protocol, which begins accumulating\n * interest based on the current Supply Rate for the asset. The user receives a quantity of\n * cTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.\n * @param mintAmount The amount of the asset to be supplied, in units of the underlying asset.\n * @return 0 on success, otherwise an Error codes\n */\n function mint(uint256 mintAmount) external returns (uint256);\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise an error code.\n */\n function redeem(uint256 redeemTokens) external returns (uint256);\n\n /**\n * @notice The redeem underlying function converts cTokens into a specified quantity of the underlying\n * asset, and returns them to the user. The amount of cTokens redeemed is equal to the quantity of\n * underlying tokens received, divided by the current Exchange Rate. The amount redeemed must be less\n * than the user's Account Liquidity and the market's available liquidity.\n * @param redeemAmount The amount of underlying to be redeemed.\n * @return 0 on success, otherwise an error code.\n */\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256);\n\n /**\n * @notice The user's underlying balance, representing their assets in the protocol, is equal to\n * the user's cToken balance multiplied by the Exchange Rate.\n * @param owner The account to get the underlying balance of.\n * @return The amount of underlying currently owned by the account.\n */\n function balanceOfUnderlying(address owner) external returns (uint256);\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view returns (uint256);\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @notice Get the supply rate per block for supplying the token to Compound.\n */\n function supplyRatePerBlock() external view returns (uint256);\n}\n" + }, + "contracts/strategies/CompoundStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Compound Strategy\n * @notice Investment strategy for investing stablecoins via Compound\n * @author Origin Protocol Inc\n */\nimport { ICERC20 } from \"./ICompound.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is InitializableAbstractStrategy {\n event SkippedWithdrawal(address asset, uint256 amount);\n\n /**\n * @dev Deposit asset into Compound\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n * @return amountDeposited Amount of asset that was deposited\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n emit Deposit(_asset, address(cToken), _amount);\n require(cToken.mint(_amount) == 0, \"cToken mint failed\");\n }\n\n /**\n * @dev Withdraw asset from Compound\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n * @return amountWithdrawn Amount of asset that was withdrawn\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n // If redeeming 0 cTokens, just skip, else COMP will revert\n uint256 cTokensToRedeem = _convertUnderlyingToCToken(cToken, _amount);\n if (cTokensToRedeem == 0) {\n emit SkippedWithdrawal(_asset, _amount);\n return;\n }\n\n emit Withdrawal(_asset, address(cToken), _amount);\n require(cToken.redeemUnderlying(_amount) == 0, \"Redeem failed\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of cToken\n ICERC20 cToken = _getCTokenFor(assetsMapped[i]);\n if (cToken.balanceOf(address(this)) > 0) {\n require(\n cToken.redeem(cToken.balanceOf(address(this))) == 0,\n \"Redeem failed\"\n );\n // Transfer entire balance to Vault\n IERC20 asset = IERC20(assetsMapped[i]);\n asset.safeTransfer(\n vaultAddress,\n asset.balanceOf(address(this))\n );\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * This includes any interest that was generated since depositing\n * Compound exchange rate between the cToken and asset gradually increases,\n * causing the cToken to be worth more corresponding asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // Balance is always with token cToken decimals\n ICERC20 cToken = _getCTokenFor(_asset);\n balance = _checkBalance(cToken);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * underlying = (cTokenAmt * exchangeRate) / 1e18\n * @param _cToken cToken for which to check balance\n * @return balance Total value of the asset in the platform\n */\n function _checkBalance(ICERC20 _cToken)\n internal\n view\n returns (uint256 balance)\n {\n uint256 cTokenBalance = _cToken.balanceOf(address(this));\n uint256 exchangeRate = _cToken.exchangeRateStored();\n // e.g. 50e8*205316390724364402565641705 / 1e18 = 1.0265..e18\n balance = cTokenBalance.mul(exchangeRate).div(1e18);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n address cToken = assetToPToken[asset];\n // Safe approval\n IERC20(asset).safeApprove(cToken, 0);\n IERC20(asset).safeApprove(cToken, uint256(-1));\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / cTokens\n * We need to approve the cToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve\n * @param _cToken This cToken has the approval approval\n */\n function _abstractSetPToken(address _asset, address _cToken) internal {\n // Safe approval\n IERC20(_asset).safeApprove(_cToken, 0);\n IERC20(_asset).safeApprove(_cToken, uint256(-1));\n }\n\n /**\n * @dev Get the cToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding cToken to this asset\n */\n function _getCTokenFor(address _asset) internal view returns (ICERC20) {\n address cToken = assetToPToken[_asset];\n require(cToken != address(0), \"cToken does not exist\");\n return ICERC20(cToken);\n }\n\n /**\n * @dev Converts an underlying amount into cToken amount\n * cTokenAmt = (underlying * 1e18) / exchangeRate\n * @param _cToken cToken for which to change\n * @param _underlying Amount of underlying to convert\n * @return amount Equivalent amount of cTokens\n */\n function _convertUnderlyingToCToken(ICERC20 _cToken, uint256 _underlying)\n internal\n view\n returns (uint256 amount)\n {\n uint256 exchangeRate = _cToken.exchangeRateStored();\n // e.g. 1e18*1e18 / 205316390724364402565641705 = 50e8\n // e.g. 1e8*1e18 / 205316390724364402565641705 = 0.45 or 0\n amount = _underlying.mul(1e18).div(exchangeRate);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool is ERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n address lpToken;\n\n constructor(address[3] memory _coins, address _lpToken) public {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(int8(18 - assetDecimals));\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint256(_index)]);\n return _amount.scaleBy(int8(assetDecimals - 18));\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint256(_index)] = _amount;\n uint256 amount = calc_withdraw_one_coin(_amount, _index);\n IERC20(coins[uint256(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external returns (uint256) {\n return 1 * 10**18;\n }\n}\n" + }, + "contracts/mocks/MintableERC20.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(uint256 value) external returns (bool);\n}\n\n/**\n * @title ERC20Mintable\n * @dev ERC20 minting logic\n */\ncontract MintableERC20 is IMintableERC20, ERC20 {\n /**\n * @dev Function to mint tokens\n * @param value The amount of tokens to mint.\n * @return A boolean that indicates if the operation was successful.\n */\n function mint(uint256 value) public returns (bool) {\n _mint(msg.sender, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/MockWETH.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"WETH\";\n string public constant name = \"WETH\";\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"USDT\";\n string public constant name = \"USDT Coin\";\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"USDC\";\n string public constant name = \"USD Coin\";\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"TUSD\";\n string public constant name = \"TrueUSD\";\n}\n" + }, + "contracts/mocks/MockNonStandardToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"NonStandardToken\";\n string public constant name = \"NonStandardToken\";\n\n function transfer(address recipient, uint256 amount) public returns (bool) {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n}\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"Uniswap V2\";\n string public constant name = \"UNI-V2\";\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) public MockUniswapPair(_token0, _token1, _reserve0, _reserve1) {}\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) public {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view returns (address) {\n return tok0;\n }\n\n function token1() external view returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over multiple different blocks because then it wouldn't be a continuous reserve factor over that blockTimestamp,\n // this assumes an even reserve ratio all the way through\n function price0CumulativeLast() external view returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\n}\n" + }, + "contracts/mocks/MockEvilDAI.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract MockEvilDAI is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"DAI\";\n string public constant name = \"DAI\";\n address host;\n address realCoin;\n\n constructor(address _host, address _realCoin) public {\n host = _host;\n realCoin = _realCoin;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _amount\n ) public returns (bool) {\n // call mint again!\n if (_amount != 69) {\n IVault(host).mint(address(this), 69, 0);\n }\n return true;\n }\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IVault {\n event AssetSupported(address _asset);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event DepositsPaused();\n event DepositsUnpaused();\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setPriceProvider(address _priceProvider) external;\n\n function priceProvider() external view returns (address);\n\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\n\n function redeemFeeBps() external view returns (uint256);\n\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setRebaseThreshold(uint256 _threshold) external;\n\n function rebaseThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setUniswapAddr(address _address) external;\n\n function uniswapAddr() external view returns (address);\n\n function supportAsset(address _asset) external;\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external;\n\n function assetDefaultStrategies(address _asset)\n external\n view\n returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function harvest() external;\n\n function harvest(address _strategyAddr) external;\n\n function priceUSDMint(string calldata symbol)\n external\n view\n returns (uint256);\n\n function priceUSDRedeem(string calldata symbol)\n external\n view\n returns (uint256);\n\n // VaultCore.sol\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function mintMultiple(\n address[] calldata _assets,\n uint256[] calldata _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n function redeemAll(uint256 _minimumUnitAmount) external;\n\n function allocate() external;\n\n function reallocate(\n address _strategyFromAddress,\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function rebase() external returns (uint256);\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance() external view returns (uint256);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory);\n\n function getAssetCount() external view returns (uint256);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function isSupportedAsset(address _asset) external view returns (bool);\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Vault Contract\n * @notice The Vault contract stores assets. On a deposit, OUSD will be minted\n and sent to the depositor. On a withdrawal, OUSD will be burned and\n assets will be sent to the withdrawer. The Vault accepts deposits of\n interest form yield bearing strategies which will modify the supply\n of OUSD.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultCore is VaultStorage {\n uint256 constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n /**\n * @dev Deposit a supported asset and mint OUSD.\n * @param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @param _minimumOusdAmount Minimum OUSD to mint\n */\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 price = IMinMaxOracle(priceProvider).priceMin(\n Helpers.getSymbol(_asset)\n );\n if (price > 1e8) {\n price = 1e8;\n }\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 unitAdjustedDeposit = _amount.scaleBy(int8(18 - assetDecimals));\n uint256 priceAdjustedDeposit = _amount.mulTruncateScale(\n price.scaleBy(int8(10)), // 18-8 because oracles have 8 decimals precision\n 10**assetDecimals\n );\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedDeposit >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedDeposit);\n\n // Rebase must happen before any transfers occur.\n if (unitAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n\n // Mint matching OUSD\n oUSD.mint(msg.sender, priceAdjustedDeposit);\n\n // Transfer the deposited coins to the vault\n IERC20 asset = IERC20(_asset);\n asset.safeTransferFrom(msg.sender, address(this), _amount);\n\n if (unitAdjustedDeposit >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @dev Mint for multiple assets in the same call.\n * @param _assets Addresses of assets being deposited\n * @param _amounts Amount of each asset at the same index in the _assets\n * to deposit.\n * @param _minimumOusdAmount Minimum OUSD to mint\n */\n function mintMultiple(\n address[] calldata _assets,\n uint256[] calldata _amounts,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 unitAdjustedTotal = 0;\n uint256 priceAdjustedTotal = 0;\n uint256[] memory assetPrices = _getAssetPrices(false);\n for (uint256 j = 0; j < _assets.length; j++) {\n // In memoriam\n require(assets[_assets[j]].isSupported, \"Asset is not supported\");\n require(_amounts[j] > 0, \"Amount must be greater than 0\");\n for (uint256 i = 0; i < allAssets.length; i++) {\n if (_assets[j] == allAssets[i]) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n uint256 price = assetPrices[i];\n if (price > 1e18) {\n price = 1e18;\n }\n unitAdjustedTotal = unitAdjustedTotal.add(\n _amounts[j].scaleBy(int8(18 - assetDecimals))\n );\n priceAdjustedTotal = priceAdjustedTotal.add(\n _amounts[j].mulTruncateScale(price, 10**assetDecimals)\n );\n }\n }\n }\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedTotal >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedTotal);\n\n // Rebase must happen before any transfers occur.\n if (unitAdjustedTotal >= rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n\n oUSD.mint(msg.sender, priceAdjustedTotal);\n\n for (uint256 i = 0; i < _assets.length; i++) {\n IERC20 asset = IERC20(_assets[i]);\n asset.safeTransferFrom(msg.sender, address(this), _amounts[i]);\n }\n\n if (unitAdjustedTotal >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @dev Withdraw a supported asset and burn OUSD.\n * @param _amount Amount of OUSD to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\n public\n whenNotCapitalPaused\n nonReentrant\n {\n if (_amount > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n _redeem(_amount, _minimumUnitAmount);\n }\n\n /**\n * @dev Withdraw a supported asset and burn OUSD.\n * @param _amount Amount of OUSD to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount) internal {\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 _totalSupply = oUSD.totalSupply();\n uint256 _backingValue = _totalValue();\n\n if (maxSupplyDiff > 0) {\n // Allow a max difference of maxSupplyDiff% between\n // backing assets value and OUSD total supply\n uint256 diff = _totalSupply.divPrecisely(_backingValue);\n\n require(\n (diff > 1e18 ? diff.sub(1e18) : uint256(1e18).sub(diff)) <=\n maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n\n emit Redeem(msg.sender, _amount);\n\n // Calculate redemption outputs\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\n // Send outputs\n for (uint256 i = 0; i < allAssets.length; i++) {\n if (outputs[i] == 0) continue;\n\n IERC20 asset = IERC20(allAssets[i]);\n\n if (asset.balanceOf(address(this)) >= outputs[i]) {\n // Use Vault funds first if sufficient\n asset.safeTransfer(msg.sender, outputs[i]);\n } else {\n address strategyAddr = assetDefaultStrategies[allAssets[i]];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, allAssets[i], outputs[i]);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n }\n\n if (_minimumUnitAmount > 0) {\n uint256 unitTotal = 0;\n for (uint256 i = 0; i < outputs.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n unitTotal = unitTotal.add(\n outputs[i].scaleBy(int8(18 - assetDecimals))\n );\n }\n require(\n unitTotal >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n }\n\n oUSD.burn(msg.sender, _amount);\n\n // Until we can prove that we won't affect the prices of our assets\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n if (_amount > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n }\n\n /**\n * @notice Withdraw a supported asset and burn all OUSD.\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeemAll(uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n // Unfortunately we have to do balanceOf twice, the rebase may change\n // the account balance\n if (oUSD.balanceOf(msg.sender) > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function allocate() public whenNotCapitalPaused nonReentrant {\n _allocate();\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function _allocate() internal {\n uint256 vaultValue = _totalValueInVault();\n // Nothing in vault to allocate\n if (vaultValue == 0) return;\n uint256 strategiesValue = _totalValueInStrategies();\n // We have a method that does the same as this, gas optimisation\n uint256 calculatedTotalValue = vaultValue.add(strategiesValue);\n\n // We want to maintain a buffer on the Vault so calculate a percentage\n // modifier to multiply each amount being allocated by to enforce the\n // vault buffer\n uint256 vaultBufferModifier;\n if (strategiesValue == 0) {\n // Nothing in Strategies, allocate 100% minus the vault buffer to\n // strategies\n vaultBufferModifier = uint256(1e18).sub(vaultBuffer);\n } else {\n vaultBufferModifier = vaultBuffer.mul(calculatedTotalValue).div(\n vaultValue\n );\n if (1e18 > vaultBufferModifier) {\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\n vaultBufferModifier = uint256(1e18).sub(vaultBufferModifier);\n } else {\n // We need to let the buffer fill\n return;\n }\n }\n if (vaultBufferModifier == 0) return;\n\n // Iterate over all assets in the Vault and allocate the the appropriate\n // strategy\n for (uint256 i = 0; i < allAssets.length; i++) {\n IERC20 asset = IERC20(allAssets[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n // No balance, nothing to do here\n if (assetBalance == 0) continue;\n\n // Multiply the balance by the vault buffer modifier and truncate\n // to the scale of the asset decimals\n uint256 allocateAmount = assetBalance.mulTruncate(\n vaultBufferModifier\n );\n\n address depositStrategyAddr = assetDefaultStrategies[address(\n asset\n )];\n\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to Strategy and call deposit method to\n // mint or take required action\n asset.safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(address(asset), allocateAmount);\n }\n }\n\n // Harvest for all reward tokens above reward liquidation threshold\n for (uint256 i = 0; i < allStrategies.length; i++) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n address rewardTokenAddress = strategy.rewardTokenAddress();\n if (rewardTokenAddress != address(0)) {\n uint256 liquidationThreshold = strategy\n .rewardLiquidationThreshold();\n if (liquidationThreshold == 0) {\n // No threshold set, always harvest from strategy\n IVault(address(this)).harvest(allStrategies[i]);\n } else {\n // Check balance against liquidation threshold\n // Note some strategies don't hold the reward token balance\n // on their contract so the liquidation threshold should be\n // set to 0\n IERC20 rewardToken = IERC20(rewardTokenAddress);\n uint256 rewardTokenAmount = rewardToken.balanceOf(\n allStrategies[i]\n );\n if (rewardTokenAmount >= liquidationThreshold) {\n IVault(address(this)).harvest(allStrategies[i]);\n }\n }\n }\n }\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OUSD.\n * @return uint256 New total supply of OUSD\n */\n function rebase()\n public\n whenNotRebasePaused\n nonReentrant\n returns (uint256 newTotalSupply)\n {\n return _rebase();\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OUSD.\n * @return uint256 New total supply of OUSD\n */\n function _rebase()\n internal\n whenNotRebasePaused\n returns (uint256 newTotalSupply)\n {\n if (oUSD.totalSupply() == 0) return 0;\n uint256 oldTotalSupply = oUSD.totalSupply();\n newTotalSupply = _totalValue();\n // Only rachet upwards\n if (newTotalSupply > oldTotalSupply) {\n oUSD.changeSupply(newTotalSupply);\n }\n }\n\n /**\n * @dev Determine the total value of assets held by the vault and its\n * strategies.\n * @return uint256 value Total value in USD (1e18)\n */\n function totalValue() external view returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the assets held by the\n * vault and its strategies.\n * @return uint256 value Total value in USD (1e18)\n */\n function _totalValue() internal view returns (uint256 value) {\n return _totalValueInVault().add(_totalValueInStrategies());\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Vault.\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInVault() internal view returns (uint256 value) {\n for (uint256 y = 0; y < allAssets.length; y++) {\n IERC20 asset = IERC20(allAssets[y]);\n uint256 assetDecimals = Helpers.getDecimals(allAssets[y]);\n uint256 balance = asset.balanceOf(address(this));\n if (balance > 0) {\n value = value.add(balance.scaleBy(int8(18 - assetDecimals)));\n }\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Strategies.\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInStrategies() internal view returns (uint256 value) {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n value = value.add(_totalValueInStrategy(allStrategies[i]));\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held by strategy.\n * @param _strategyAddr Address of the strategy\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInStrategy(address _strategyAddr)\n internal\n view\n returns (uint256 value)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n for (uint256 y = 0; y < allAssets.length; y++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[y]);\n if (strategy.supportsAsset(allAssets[y])) {\n uint256 balance = strategy.checkBalance(allAssets[y]);\n if (balance > 0) {\n value = value.add(\n balance.scaleBy(int8(18 - assetDecimals))\n );\n }\n }\n }\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n for (uint256 i = 0; i < allStrategies.length; i++) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance.add(strategy.checkBalance(_asset));\n }\n }\n }\n\n /**\n * @notice Get the balance of all assets held in Vault and all strategies.\n * @return uint256 Balance of all assets (1e18)\n */\n function _checkBalance() internal view returns (uint256 balance) {\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n balance = balance.add(\n _checkBalance(allAssets[i]).scaleBy(int8(18 - assetDecimals))\n );\n }\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned\n */\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory)\n {\n return _calculateRedeemOutputs(_amount);\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned.\n * @return Array of amounts respective to the supported assets\n */\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n returns (uint256[] memory outputs)\n {\n // We always give out coins in proportion to how many we have,\n // Now if all coins were the same value, this math would easy,\n // just take the percentage of each coin, and multiply by the\n // value to be given out. But if coins are worth more than $1,\n // then we would end up handing out too many coins. We need to\n // adjust by the total value of coins.\n //\n // To do this, we total up the value of our coins, by their\n // percentages. Then divide what we would otherwise give out by\n // this number.\n //\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\n //\n // So when calculating the output, we take the percentage of\n // each coin, times the desired output value, divided by the\n // totalOutputRatio.\n //\n // For example, withdrawing: 30 OUSD:\n // DAI 33% * 30 / 1.02 = 9.80 DAI\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\n //\n // Checking these numbers:\n // 9.80 DAI * 1.06 = $10.40\n // 19.60 USDT * 1.00 = $19.60\n //\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\n\n uint256 assetCount = getAssetCount();\n uint256[] memory assetPrices = _getAssetPrices(true);\n uint256[] memory assetBalances = new uint256[](assetCount);\n uint256[] memory assetDecimals = new uint256[](assetCount);\n uint256 totalBalance = 0;\n uint256 totalOutputRatio = 0;\n outputs = new uint256[](assetCount);\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mul(redeemFeeBps).div(10000);\n _amount = _amount.sub(redeemFee);\n }\n\n // Calculate assets balances and decimals once,\n // for a large gas savings.\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 balance = _checkBalance(allAssets[i]);\n uint256 decimals = Helpers.getDecimals(allAssets[i]);\n assetBalances[i] = balance;\n assetDecimals[i] = decimals;\n totalBalance = totalBalance.add(\n balance.scaleBy(int8(18 - decimals))\n );\n }\n // Calculate totalOutputRatio\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 price = assetPrices[i];\n // Never give out more than one\n // stablecoin per dollar of OUSD\n if (price < 1e18) {\n price = 1e18;\n }\n uint256 ratio = assetBalances[i]\n .scaleBy(int8(18 - assetDecimals[i]))\n .mul(price)\n .div(totalBalance);\n totalOutputRatio = totalOutputRatio.add(ratio);\n }\n // Calculate final outputs\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\n for (uint256 i = 0; i < allAssets.length; i++) {\n outputs[i] = assetBalances[i].mul(factor).div(totalBalance);\n }\n }\n\n /**\n * @notice Get an array of the supported asset prices in USD.\n * @return uint256[] Array of asset prices in USD (1e18)\n */\n function _getAssetPrices(bool useMax)\n internal\n view\n returns (uint256[] memory assetPrices)\n {\n assetPrices = new uint256[](getAssetCount());\n\n IMinMaxOracle oracle = IMinMaxOracle(priceProvider);\n // Price from Oracle is returned with 8 decimals\n // _amount is in assetDecimals\n\n for (uint256 i = 0; i < allAssets.length; i++) {\n string memory symbol = Helpers.getSymbol(allAssets[i]);\n // Get all the USD prices of the asset in 1e18\n if (useMax) {\n assetPrices[i] = oracle.priceMax(symbol).scaleBy(int8(18 - 8));\n } else {\n assetPrices[i] = oracle.priceMin(symbol).scaleBy(int8(18 - 8));\n }\n }\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @dev Return the number of assets suppported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return allAssets.length;\n }\n\n /**\n * @dev Return all asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n return allAssets;\n }\n\n /**\n * @dev Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n function isSupportedAsset(address _asset) external view returns (bool) {\n return assets[_asset].isSupported;\n }\n\n /**\n * @dev Falldown to the admin implementation\n * @notice This is a catch all for all functions not declared in core\n */\n function() external payable {\n bytes32 slot = adminImplPosition;\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize)\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas, sload(slot), 0, calldatasize, 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize)\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize)\n }\n default {\n return(0, returndatasize)\n }\n }\n }\n}\n" + }, + "contracts/oracle/MixOracle.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD MixOracle Contract\n * @notice The MixOracle pulls exchange rate from multiple oracles and returns\n * min and max values.\n * @author Origin Protocol Inc\n */\nimport { IPriceOracle } from \"../interfaces/IPriceOracle.sol\";\nimport { IEthUsdOracle } from \"../interfaces/IEthUsdOracle.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract MixOracle is IMinMaxOracle, Governable {\n event DriftsUpdated(uint256 _minDrift, uint256 _maxDrift);\n event EthUsdOracleRegistered(address _oracle);\n event EthUsdOracleDeregistered(address _oracle);\n event TokenOracleRegistered(\n string symbol,\n address[] ethOracles,\n address[] usdOracles\n );\n\n address[] public ethUsdOracles;\n\n struct MixConfig {\n address[] usdOracles;\n address[] ethOracles;\n }\n\n mapping(bytes32 => MixConfig) configs;\n\n uint256 constant MAX_INT = 2**256 - 1;\n uint256 public maxDrift;\n uint256 public minDrift;\n\n constructor(uint256 _maxDrift, uint256 _minDrift) public {\n maxDrift = _maxDrift;\n minDrift = _minDrift;\n emit DriftsUpdated(_minDrift, _maxDrift);\n }\n\n function setMinMaxDrift(uint256 _minDrift, uint256 _maxDrift)\n public\n onlyGovernor\n {\n minDrift = _minDrift;\n maxDrift = _maxDrift;\n emit DriftsUpdated(_minDrift, _maxDrift);\n }\n\n /**\n * @notice Adds an oracle to the list of oracles to pull data from.\n * @param oracle Address of an oracle that implements the IEthUsdOracle interface.\n **/\n function registerEthUsdOracle(address oracle) public onlyGovernor {\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n require(ethUsdOracles[i] != oracle, \"Oracle already registered.\");\n }\n ethUsdOracles.push(oracle);\n emit EthUsdOracleRegistered(oracle);\n }\n\n /**\n * @notice Removes an oracle to the list of oracles to pull data from.\n * @param oracle Address of an oracle that implements the IEthUsdOracle interface.\n **/\n function unregisterEthUsdOracle(address oracle) public onlyGovernor {\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n if (ethUsdOracles[i] == oracle) {\n // swap with the last element of the array, and then delete last element (could be itself)\n ethUsdOracles[i] = ethUsdOracles[ethUsdOracles.length - 1];\n delete ethUsdOracles[ethUsdOracles.length - 1];\n emit EthUsdOracleDeregistered(oracle);\n ethUsdOracles.pop();\n return;\n }\n }\n revert(\"Oracle not found\");\n }\n\n /**\n * @notice Adds an oracle to the list of oracles to pull data from.\n * @param ethOracles Addresses of oracles that implements the IEthUsdOracle interface and answers for this asset\n * @param usdOracles Addresses of oracles that implements the IPriceOracle interface and answers for this asset\n **/\n function registerTokenOracles(\n string calldata symbol,\n address[] calldata ethOracles,\n address[] calldata usdOracles\n ) external onlyGovernor {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n config.ethOracles = ethOracles;\n config.usdOracles = usdOracles;\n emit TokenOracleRegistered(symbol, ethOracles, usdOracles);\n }\n\n /**\n * @notice Returns the min price of an asset in USD.\n * @return symbol Asset symbol. Example: \"DAI\"\n * @return price Min price from all the oracles, in USD with 8 decimal digits.\n **/\n function priceMin(string calldata symbol)\n external\n view\n returns (uint256 price)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n uint256 ep;\n uint256 p; //holder variables\n price = MAX_INT;\n if (config.ethOracles.length > 0) {\n ep = MAX_INT;\n for (uint256 i = 0; i < config.ethOracles.length; i++) {\n p = IEthUsdOracle(config.ethOracles[i]).tokEthPrice(symbol);\n if (ep > p) {\n ep = p;\n }\n }\n price = ep;\n ep = MAX_INT;\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n p = IEthUsdOracle(ethUsdOracles[i]).ethUsdPrice();\n if (ep > p) {\n ep = p;\n }\n }\n if (price != MAX_INT && ep != MAX_INT) {\n // tokEthPrice has precision of 8 which ethUsdPrice has precision of 6\n // we want precision of 8\n price = (price * ep) / 1e6;\n }\n }\n\n if (config.usdOracles.length > 0) {\n for (uint256 i = 0; i < config.usdOracles.length; i++) {\n // upscale by 2 since price oracles are precision 6\n p = IPriceOracle(config.usdOracles[i]).price(symbol) * 1e2;\n if (price > p) {\n price = p;\n }\n }\n }\n require(price <= maxDrift, \"Price exceeds maxDrift\");\n require(price >= minDrift, \"Price below minDrift\");\n require(\n price != MAX_INT,\n \"None of our oracles returned a valid min price!\"\n );\n }\n\n /**\n * @notice Returns max price of an asset in USD.\n * @return symbol Asset symbol. Example: \"DAI\"\n * @return price Max price from all the oracles, in USD with 8 decimal digits.\n **/\n function priceMax(string calldata symbol)\n external\n view\n returns (uint256 price)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n uint256 ep;\n uint256 p; //holder variables\n price = 0;\n if (config.ethOracles.length > 0) {\n ep = 0;\n for (uint256 i = 0; i < config.ethOracles.length; i++) {\n p = IEthUsdOracle(config.ethOracles[i]).tokEthPrice(symbol);\n if (ep < p) {\n ep = p;\n }\n }\n price = ep;\n ep = 0;\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n p = IEthUsdOracle(ethUsdOracles[i]).ethUsdPrice();\n if (ep < p) {\n ep = p;\n }\n }\n if (price != 0 && ep != 0) {\n // tokEthPrice has precision of 8 which ethUsdPrice has precision of 6\n // we want precision of 8\n price = (price * ep) / 1e6;\n }\n }\n\n if (config.usdOracles.length > 0) {\n for (uint256 i = 0; i < config.usdOracles.length; i++) {\n // upscale by 2 since price oracles are precision 6\n p = IPriceOracle(config.usdOracles[i]).price(symbol) * 1e2;\n if (price < p) {\n price = p;\n }\n }\n }\n\n require(price <= maxDrift, \"Price exceeds maxDrift\");\n require(price >= minDrift, \"Price below minDrift\");\n require(price != 0, \"None of our oracles returned a valid max price!\");\n }\n\n /**\n * @notice Returns the length of the usdOracles array for a given token\n * @param symbol Asset symbol. Example: \"DAI\"\n * @return length of the USD oracles array\n **/\n function getTokenUSDOraclesLength(string calldata symbol)\n external\n view\n returns (uint256)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.usdOracles.length;\n }\n\n /**\n * @notice Returns the address of a specific USD oracle\n * @param symbol Asset symbol. Example: \"DAI\"\n * @param idx Index of the array value to return\n * @return address of the oracle\n **/\n function getTokenUSDOracle(string calldata symbol, uint256 idx)\n external\n view\n returns (address)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.usdOracles[idx];\n }\n\n /**\n * @notice Returns the length of the ethOracles array for a given token\n * @param symbol Asset symbol. Example: \"DAI\"\n * @return length of the ETH oracles array\n **/\n function getTokenETHOraclesLength(string calldata symbol)\n external\n view\n returns (uint256)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.ethOracles.length;\n }\n\n /**\n * @notice Returns the address of a specific ETH oracle\n * @param symbol Asset symbol. Example: \"DAI\"\n * @param idx Index of the array value to return\n * @return address of the oracle\n **/\n function getTokenETHOracle(string calldata symbol, uint256 idx)\n external\n view\n returns (address)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.ethOracles[idx];\n }\n}\n" + }, + "contracts/interfaces/IPriceOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IEthUsdOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/oracle/ChainlinkOracle.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD ChainlinkOracle Contract\n * @author Origin Protocol Inc\n */\nimport \"./AggregatorV3Interface.sol\";\nimport { IPriceOracle } from \"../interfaces/IPriceOracle.sol\";\nimport { IEthUsdOracle } from \"../interfaces/IEthUsdOracle.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract ChainlinkOracle is IEthUsdOracle, IPriceOracle, Governable {\n event FeedRegistered(address _feed, string _symbol, bool _directToUsd);\n\n address ethFeed;\n\n struct FeedConfig {\n address feed;\n uint8 decimals;\n bool directToUsd;\n }\n\n mapping(bytes32 => FeedConfig) feeds;\n\n uint8 ethDecimals;\n\n string constant ethSymbol = \"ETH\";\n bytes32 constant ethHash = keccak256(abi.encodePacked(ethSymbol));\n\n constructor(address ethFeed_) public {\n ethFeed = ethFeed_;\n ethDecimals = AggregatorV3Interface(ethFeed_).decimals();\n }\n\n function registerFeed(\n address feed,\n string memory symbol,\n bool directToUsd\n ) public onlyGovernor {\n FeedConfig storage config = feeds[keccak256(abi.encodePacked(symbol))];\n\n config.feed = feed;\n config.decimals = AggregatorV3Interface(feed).decimals();\n config.directToUsd = directToUsd;\n\n emit FeedRegistered(feed, symbol, directToUsd);\n }\n\n function getLatestPrice(address feed) internal view returns (int256) {\n (\n uint80 roundID,\n int256 price,\n uint256 startedAt,\n uint256 timeStamp,\n uint80 answeredInRound\n ) = AggregatorV3Interface(feed).latestRoundData();\n // silence\n roundID;\n startedAt;\n timeStamp;\n answeredInRound;\n return price;\n }\n\n function ethUsdPrice() external view returns (uint256) {\n return (uint256(getLatestPrice(ethFeed)) /\n (uint256(10)**(ethDecimals - 6)));\n }\n\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256)\n {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n require(config.directToUsd, \"Price is not direct to usd\");\n require(tPrice > 0, \"Price must be greater than zero\");\n return uint256(tPrice);\n }\n\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256)\n {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n require(!config.directToUsd, \"Price is not in terms of ETH\");\n require(tPrice > 0, \"Price must be greater than zero\");\n //attempt to return 8 digit precision here\n return uint256(tPrice) / (uint256(10)**(config.decimals - 8));\n }\n\n // This actually calculate the latest price from outside oracles\n // It's a view but substantially more costly in terms of calculation\n function price(string calldata symbol) external view returns (uint256) {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n\n if (ethHash == tokenSymbolHash) {\n return (uint256(getLatestPrice(ethFeed)) /\n (uint256(10)**(ethDecimals - 6)));\n } else {\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n if (config.directToUsd) {\n require(tPrice > 0, \"Price must be greater than zero\");\n return uint256(tPrice);\n } else {\n int256 ethPrice = getLatestPrice(ethFeed); // grab the eth price from the open oracle\n require(\n tPrice > 0 && ethPrice > 0,\n \"Both eth and price must be greater than zero\"\n );\n //not actually sure why it's 6 units here, this is just to match with openoracle for now\n return\n mul(uint256(tPrice), uint256(ethPrice)) /\n (uint256(10)**(ethDecimals + config.decimals - 6));\n }\n }\n }\n\n /// @dev Overflow proof multiplication\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a == 0) return 0;\n uint256 c = a * b;\n require(c / a == b, \"multiplication overflow\");\n return c;\n }\n}\n" + }, + "contracts/oracle/AggregatorV3Interface.sol": { + "content": "pragma solidity ^0.5.11;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256) {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol) external view returns (uint256) {\n uint256[] storage pMinMax = pricesMinMax[keccak256(\n abi.encodePacked(symbol)\n )];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol) external view returns (uint256) {\n uint256[] storage pMinMax = pricesMinMax[keccak256(\n abi.encodePacked(symbol)\n )];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockChainlinkOracleFeed.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../oracle/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) public {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view returns (uint8) {\n return numDecimals;\n }\n\n function description() external view returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external view returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\nimport { VaultInitializer } from \"../vault/VaultInitializer.sol\";\n\ncontract MockVault is VaultCore, VaultInitializer {\n uint256 storedTotalValue;\n\n function setTotalValue(uint256 _totalValue) public {\n storedTotalValue = _totalValue;\n }\n\n function totalValue() external view returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view returns (uint256) {\n return storedTotalValue;\n }\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultInitializer is VaultStorage {\n function initialize(address _priceProvider, address _ousd)\n external\n onlyGovernor\n initializer\n {\n require(_priceProvider != address(0), \"PriceProvider address is zero\");\n require(_ousd != address(0), \"oUSD address is zero\");\n\n oUSD = OUSD(_ousd);\n\n priceProvider = _priceProvider;\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial redeem fee of 0 basis points\n redeemFeeBps = 0;\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Threshold for rebasing\n rebaseThreshold = 1000e18;\n }\n}\n" + }, + "contracts/vault/Vault.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The VaultInitializer sets up the initial contract.\n * @author Origin Protocol Inc\n */\nimport { VaultInitializer } from \"./VaultInitializer.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\ncontract Vault is VaultInitializer, VaultAdmin {}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function increaseAllowance(address _spender, uint256 _addedValue) public {\n oUSD.increaseAllowance(_spender, _addedValue);\n }\n\n function mintOusd(\n address _vaultContract,\n address _asset,\n uint256 _amount\n ) public {\n IVault(_vaultContract).mint(_asset, _amount, 0);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).redeem(_amount, 0);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/token/OUSDReset.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract OUSDReset is OUSD {\n /**\n * Reset function to restore initial state.\n * TODO Remove\n */\n function reset() external onlyGovernor {\n _name = \"Origin Dollar\";\n _symbol = \"OUSD\";\n _decimals = 18;\n rebasingCreditsPerToken = 1e18;\n }\n\n function setVaultAddress(address _vaultAddress) external onlyGovernor {\n vaultAddress = _vaultAddress;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) public {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/liquidity/LiquidityReward.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\n\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(\n pool.lpToken.balanceOf(address(this))\n ),\n totalRewardDebt\n );\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (lpSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && lpSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(lpSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (lpSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n uint256 pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n if (pending > 0) {\n reward.safeTransfer(msg.sender, pending);\n emit Claim(msg.sender, pending);\n }\n newDebt += int256(pending);\n }\n\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n require(\n success,\n \"Timelock::executeTransaction: Transaction execution reverted.\"\n );\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/governance/Governor.sol": { + "content": "pragma solidity 0.5.11;\npragma experimental ABIEncoderV2;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 16;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState { Pending, Queued, Expired, Executed }\n\n constructor(address admin_, uint256 delay_)\n public\n Timelock(admin_, delay_)\n {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp.add(delay);\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta.add(GRACE_PERIOD)) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n )],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/crytic/PropertiesOUSDTransferable.sol": { + "content": "import \"./interfaces.sol\";\nimport \"../token/OUSD.sol\";\n\ncontract PropertiesOUSDTransferable is CryticInterface, OUSD {\n function init_total_supply() public returns (bool) {\n return\n this.totalSupply() >= 0 && this.totalSupply() == initialTotalSupply;\n }\n\n function init_owner_balance() public returns (bool) {\n return initialBalance_owner == this.balanceOf(crytic_owner);\n }\n\n function init_user_balance() public returns (bool) {\n return initialBalance_user == this.balanceOf(crytic_user);\n }\n\n function init_attacker_balance() public returns (bool) {\n return initialBalance_attacker == this.balanceOf(crytic_attacker);\n }\n\n function init_caller_balance() public returns (bool) {\n return this.balanceOf(msg.sender) > 0;\n }\n\n function init_total_supply_is_balances() public returns (bool) {\n return\n this.balanceOf(crytic_owner) +\n this.balanceOf(crytic_user) +\n this.balanceOf(crytic_attacker) ==\n this.totalSupply();\n }\n\n function crytic_zero_always_empty_ERC20Properties() public returns (bool) {\n return this.balanceOf(address(0x0)) == 0;\n }\n\n function crytic_approve_overwrites() public returns (bool) {\n bool approve_return;\n approve_return = approve(crytic_user, 10);\n require(approve_return);\n approve_return = approve(crytic_user, 20);\n require(approve_return);\n return this.allowance(msg.sender, crytic_user) == 20;\n }\n\n function crytic_less_than_total_ERC20Properties() public returns (bool) {\n return this.balanceOf(msg.sender) <= totalSupply();\n }\n\n function crytic_revert_transfer_to_zero_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n if (this.balanceOf(msg.sender) == 0) {\n revert();\n }\n return transfer(address(0x0), this.balanceOf(msg.sender));\n }\n\n function crytic_revert_transferFrom_to_zero_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n if (balance == 0) {\n revert();\n }\n approve(msg.sender, balance);\n return\n transferFrom(msg.sender, address(0x0), this.balanceOf(msg.sender));\n }\n\n function crytic_self_transferFrom_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool approve_return = approve(msg.sender, balance);\n bool transfer_return = transferFrom(msg.sender, msg.sender, balance);\n return\n (this.balanceOf(msg.sender) == balance) &&\n approve_return &&\n transfer_return;\n }\n\n function crytic_self_transferFrom_to_other_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool approve_return = approve(msg.sender, balance);\n address other = crytic_user;\n if (other == msg.sender) {\n other = crytic_owner;\n }\n bool transfer_return = transferFrom(msg.sender, other, balance);\n return\n (this.balanceOf(msg.sender) == 0) &&\n approve_return &&\n transfer_return;\n }\n\n function crytic_self_transfer_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool transfer_return = transfer(msg.sender, balance);\n return (this.balanceOf(msg.sender) == balance) && transfer_return;\n }\n\n function crytic_transfer_to_other_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n address other = crytic_user;\n if (other == msg.sender) {\n other = crytic_owner;\n }\n if (balance >= 1) {\n bool transfer_other = transfer(other, 1);\n return\n (this.balanceOf(msg.sender) == balance - 1) &&\n (this.balanceOf(other) >= 1) &&\n transfer_other;\n }\n return true;\n }\n\n function crytic_revert_transfer_to_user_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n if (balance == (2**128 - 1)) return true;\n bool transfer_other = transfer(crytic_user, balance + 1);\n return transfer_other;\n }\n}\n" + }, + "contracts/crytic/interfaces.sol": { + "content": "contract CryticInterface {\n address internal crytic_owner = address(\n 0x627306090abaB3A6e1400e9345bC60c78a8BEf57\n );\n address internal crytic_user = address(\n 0xf17f52151EbEF6C7334FAD080c5704D77216b732\n );\n address internal crytic_attacker = address(\n 0xC5fdf4076b8F3A5357c5E395ab970B5B54098Fef\n );\n uint256 internal initialTotalSupply;\n uint256 internal initialBalance_owner;\n uint256 internal initialBalance_user;\n uint256 internal initialBalance_attacker;\n}\n" + }, + "contracts/crytic/TestOUSDTransferable.sol": { + "content": "import \"./PropertiesOUSDTransferable.sol\";\n\ncontract TestOUSDTransferable is PropertiesOUSDTransferable {\n constructor() public {\n // Existing addresses:\n // - crytic_owner: If the contract has an owner, it must be crytic_owner\n // - crytic_user: Legitimate user\n // - crytic_attacker: Attacker\n //\n // Add below a minimal configuration:\n // - crytic_owner must have some tokens\n // - crytic_user must have some tokens\n // - crytic_attacker must have some tokens\n\n rebasingCredits = 0;\n rebasingCreditsPerToken = 1e18;\n vaultAddress = crytic_owner;\n nonRebasingSupply = 0;\n\n initialTotalSupply = ~uint128(0);\n initialBalance_owner = initialTotalSupply / 3;\n _mint(crytic_owner, initialBalance_owner);\n initialBalance_user = initialTotalSupply / 3;\n _mint(crytic_user, initialBalance_user);\n initialBalance_attacker = initialTotalSupply / 3;\n _mint(crytic_attacker, initialBalance_attacker);\n }\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress\n ) external {\n revert();\n } // We don't need to call initialize\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"DAI\";\n string public constant name = \"DAI\";\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"COMP\";\n string public constant name = \"COMP\";\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"CRV\";\n string public constant name = \"Curve DAO Token\";\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../MintableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"3Crv\";\n string public constant name = \"Curve.fi DAI/USDC/USDT\";\n\n function mint(address to, uint256 value) public returns (bool) {\n _mint(to, value);\n return true;\n }\n\n function burnFrom(address from, uint256 value) public returns (bool) {\n _burn(from, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) public {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external {\n IERC20(lpToken).transfer(msg.sender, _value);\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/strategies/AaveStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Aave Strategy\n * @notice Investment strategy for investing stablecoins via Aave\n * @author Origin Protocol Inc\n */\nimport \"./IAave.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract AaveStrategy is InitializableAbstractStrategy {\n uint16 constant referralCode = 92;\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n * @return amountDeposited Amount of asset that was deposited\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n\n IAaveAToken aToken = _getATokenFor(_asset);\n emit Deposit(_asset, address(aToken), _amount);\n _getLendingPool().deposit(_asset, _amount, referralCode);\n }\n\n /**\n * @dev Withdraw asset from Aave\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n * @return amountWithdrawn Amount of asset that was withdrawn\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n IAaveAToken aToken = _getATokenFor(_asset);\n emit Withdrawal(_asset, address(aToken), _amount);\n aToken.redeem(_amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of aToken\n IAaveAToken aToken = _getATokenFor(assetsMapped[i]);\n uint256 balance = aToken.balanceOf(address(this));\n if (balance > 0) {\n aToken.redeem(balance);\n // Transfer entire balance to Vault\n IERC20 asset = IERC20(assetsMapped[i]);\n asset.safeTransfer(\n vaultAddress,\n asset.balanceOf(address(this))\n );\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // Balance is always with token aToken decimals\n IAaveAToken aToken = _getATokenFor(_asset);\n balance = aToken.balanceOf(address(this));\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding aToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external onlyGovernor nonReentrant {\n uint256 assetCount = assetsMapped.length;\n address lendingPoolVault = _getLendingPoolCore();\n // approve the pool to spend the bAsset\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n // Safe approval\n IERC20(asset).safeApprove(lendingPoolVault, 0);\n IERC20(asset).safeApprove(lendingPoolVault, uint256(-1));\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / aTokens\n * We need to approve the aToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve\n * @param _aToken This aToken has the approval approval\n */\n function _abstractSetPToken(address _asset, address _aToken) internal {\n address lendingPoolVault = _getLendingPoolCore();\n IERC20(_asset).safeApprove(lendingPoolVault, 0);\n IERC20(_asset).safeApprove(lendingPoolVault, uint256(-1));\n }\n\n /**\n * @dev Get the aToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding aToken to this asset\n */\n function _getATokenFor(address _asset) internal view returns (IAaveAToken) {\n address aToken = assetToPToken[_asset];\n require(aToken != address(0), \"aToken does not exist\");\n return IAaveAToken(aToken);\n }\n\n /**\n * @dev Get the current address of the Aave lending pool, which is the gateway to\n * depositing.\n * @return Current lending pool implementation\n */\n function _getLendingPool() internal view returns (IAaveLendingPool) {\n address lendingPool = ILendingPoolAddressesProvider(platformAddress)\n .getLendingPool();\n require(lendingPool != address(0), \"Lending pool does not exist\");\n return IAaveLendingPool(lendingPool);\n }\n\n /**\n * @dev Get the current address of the Aave lending pool core, which stores all the\n * reserve tokens in its vault.\n * @return Current lending pool core address\n */\n function _getLendingPoolCore() internal view returns (address payable) {\n address payable lendingPoolCore = ILendingPoolAddressesProvider(\n platformAddress\n )\n .getLendingPoolCore();\n require(\n lendingPoolCore != address(uint160(address(0))),\n \"Lending pool core does not exist\"\n );\n return lendingPoolCore;\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport {\n BaseUpgradeabilityProxy\n} from \"@openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is\n Governable,\n BaseUpgradeabilityProxy\n{\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes memory _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _changeGovernor(_initGovernor);\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport './Proxy.sol';\nimport '../utils/Address.sol';\n\n/**\n * @title BaseUpgradeabilityProxy\n * @dev This contract implements a proxy that allows to change the\n * implementation address to which it will delegate.\n * Such a change is called an implementation upgrade.\n */\ncontract BaseUpgradeabilityProxy is Proxy {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(OpenZeppelinUpgradesAddress.isContract(newImplementation), \"Cannot set a proxy implementation to a non-contract address\");\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/upgradeability/Proxy.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @title Proxy\n * @dev Implements delegation of calls to other contracts, with proper\n * forwarding of return values and bubbling of failures.\n * It defines a fallback function that delegates all calls to the address\n * returned by the abstract _implementation() internal function.\n */\ncontract Proxy {\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n function () payable external {\n _fallback();\n }\n\n /**\n * @return The Address of the implementation.\n */\n function _implementation() internal view returns (address);\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param implementation Address to delegate.\n */\n function _delegate(address implementation) internal {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize)\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize)\n\n switch result\n // delegatecall returns 0 on error.\n case 0 { revert(0, returndatasize) }\n default { return(0, returndatasize) }\n }\n }\n\n /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {\n }\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/utils/Address.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * Utility library of inline functions on addresses\n *\n * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol\n * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts\n * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the\n * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version.\n */\nlibrary OpenZeppelinUpgradesAddress {\n /**\n * Returns whether the target address is a contract\n * @dev This function will return false if invoked during the constructor of a contract,\n * as the code is not actually created until after the constructor finishes.\n * @param account address of the account to check\n * @return whether the target address is a contract\n */\n function isContract(address account) internal view returns (bool) {\n uint256 size;\n // XXX Currently there is no better way to check if there is a contract in an address\n // than to check the size of the code at that address.\n // See https://ethereum.stackexchange.com/a/14016/36603\n // for more details about how this works.\n // TODO Check this again before the Serenity release, because all addresses will be\n // contracts then.\n // solhint-disable-next-line no-inline-assembly\n assembly { size := extcodesize(account) }\n return size > 0;\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n InitializeGovernedUpgradeabilityProxy\n} from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/deployments/rinkeby/.migrations.json b/contracts/deployments/rinkeby/.migrations.json index eaae23dac9..93cca35ba1 100644 --- a/contracts/deployments/rinkeby/.migrations.json +++ b/contracts/deployments/rinkeby/.migrations.json @@ -6,5 +6,6 @@ "004_single_asset_staking": 1608185799, "007_upgrade_single_asset_staking": 1608526958, "008_ousd_reset": 1609285987, - "009_ousd_fix": 1609652662 + "009_ousd_fix": 1609652662, + "010_upgrade_single_asset_staking": 1609968697 } \ No newline at end of file diff --git a/contracts/deployments/rinkeby/SingleAssetStaking.json b/contracts/deployments/rinkeby/SingleAssetStaking.json index 3941a7789c..e9110dc918 100644 --- a/contracts/deployments/rinkeby/SingleAssetStaking.json +++ b/contracts/deployments/rinkeby/SingleAssetStaking.json @@ -1,5 +1,5 @@ { - "address": "0x13Cce8457Bd81b6935E760599dc523a95B9527e8", + "address": "0xc21B8c7F598bD0b4e383ec8C0AAE2b8519C2Bd65", "abi": [ { "constant": true, @@ -611,6 +611,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rate", + "type": "uint256" } ], "name": "Staked", @@ -630,6 +642,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" } ], "name": "Withdrawn", @@ -756,42 +774,42 @@ "type": "event" } ], - "transactionHash": "0xd60e9ea5df43565ea051d58219ad172298d0bb7ae2ceba9a6845883572003e81", + "transactionHash": "0xea728443150ee0ffcae1489fa02c1196fcc8bb7961a4c762415c19cd63c6438b", "receipt": { "to": null, "from": "0xD85A569F3C26f81070544451131c742283360400", - "contractAddress": "0x13Cce8457Bd81b6935E760599dc523a95B9527e8", - "transactionIndex": 4, - "gasUsed": "2498884", - "logsBloom": "0x00000000400000000000000010000000000000000000000000000000000000000000000000000000000000000000000000008000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000020000000000000000000000000000000000000000400000000000000000000000000", - "blockHash": "0x7aabd154ca989af2b3360e8a1c2cdc2c62f4e84244a6145009bdce8243e8c56b", - "transactionHash": "0xd60e9ea5df43565ea051d58219ad172298d0bb7ae2ceba9a6845883572003e81", + "contractAddress": "0xc21B8c7F598bD0b4e383ec8C0AAE2b8519C2Bd65", + "transactionIndex": 2, + "gasUsed": "2518562", + "logsBloom": "0x00000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000004000000000000000000000000000000000000000010000000000000000000000400000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000020000000000000000000000010000000000000000400000000000000000000000000", + "blockHash": "0x91051101e6aa2775b31e193cd24e193b55d12e5045f0f77f1a8bacb92cccf1a7", + "transactionHash": "0xea728443150ee0ffcae1489fa02c1196fcc8bb7961a4c762415c19cd63c6438b", "logs": [ { - "transactionIndex": 4, - "blockNumber": 7756594, - "transactionHash": "0xd60e9ea5df43565ea051d58219ad172298d0bb7ae2ceba9a6845883572003e81", - "address": "0x13Cce8457Bd81b6935E760599dc523a95B9527e8", + "transactionIndex": 2, + "blockNumber": 7849411, + "transactionHash": "0xea728443150ee0ffcae1489fa02c1196fcc8bb7961a4c762415c19cd63c6438b", + "address": "0xc21B8c7F598bD0b4e383ec8C0AAE2b8519C2Bd65", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000d85a569f3c26f81070544451131c742283360400" ], "data": "0x", - "logIndex": 12, - "blockHash": "0x7aabd154ca989af2b3360e8a1c2cdc2c62f4e84244a6145009bdce8243e8c56b" + "logIndex": 0, + "blockHash": "0x91051101e6aa2775b31e193cd24e193b55d12e5045f0f77f1a8bacb92cccf1a7" } ], - "blockNumber": 7756594, - "cumulativeGasUsed": "2774998", + "blockNumber": 7849411, + "cumulativeGasUsed": "2560562", "status": 1, "byzantium": true }, "args": [], - "solcInputHash": "a0c4b4d689b13a774a7e3a992025a384", - "metadata": "{\"compiler\":{\"version\":\"0.5.11+commit.22be8592.mod\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAllStakes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"internalType\":\"struct SingleAssetStaking.Stake[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalOutstanding\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"setDurationRates\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_stakeType\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_rootHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_proofDepth\",\"type\":\"uint256\"}],\"name\":\"setAirDropRoot\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"name\":\"airDroppedStake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stakeWithSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"stakingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"durationRewardRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalCurrentHoldings\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalStaked\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"name\":\"airDroppedStakeClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"durations\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllDurations\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"dropRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingToken\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalExpectedRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllRates\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"yes\",\"type\":\"bool\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"durations\",\"type\":\"uint256[]\"}],\"name\":\"NewDurations\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"rates\",\"type\":\"uint256[]\"}],\"name\":\"NewRates\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"rootHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"proofDepth\",\"type\":\"uint256\"}],\"name\":\"NewAirDropRootHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])\":{\"details\":\"Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from an airdrop or a compensation program. Only 1 of each type is allowed per user. The proof must match the root hash\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"index\":\"Number that is zero base index of the stake in the payout entry\",\"merkleProof\":\"Array of proofs for that amount\",\"rate\":\"Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\",\"stakeType\":\"Number that represent the type of the stake, must not be 0 which is user stake\"}},\"airDroppedStakeClaimed(address,uint8)\":{\"details\":\"Has the airdropped stake already been claimed\"},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"durationRewardRate(uint256)\":{\"details\":\"Find the rate that corresponds to a given duration\",\"params\":{\"_duration\":\"Number of seconds\"}},\"exit()\":{\"details\":\"Exit out of all possible stakes\"},\"getAllStakes(address)\":{\"details\":\"Return all the stakes paid and unpaid for a given user\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,uint256[],uint256[])\":{\"details\":\"Initialize the contracts, sets up durations, rates, and preApprover for preApproved contracts can only be called once\",\"params\":{\"_durations\":\"Array of allowed durations in seconds\",\"_rates\":\"Array of rates(0.3 is 30%) that correspond to the allowed durations in 1e18 precision\",\"_stakingToken\":\"Address of the token that we are staking\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"setAirDropRoot(uint8,bytes32,uint256)\":{\"details\":\"Set air drop root for a specific stake type\",\"params\":{\"_proofDepth\":\"Depth of the Merklke Tree\",\"_rootHash\":\"Root hash of the Merkle Tree\",\"_stakeType\":\"Type of staking must be greater than 0\"}},\"setDurationRates(uint256[],uint256[])\":{\"details\":\"Set new durations and rates will not effect existing stakes\",\"params\":{\"_durations\":\"Array of durations in seconds\",\"_rates\":\"Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\"}},\"stake(uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. User must have already approved the contract for specified amount.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\"}},\"stakeWithSender(address,uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. This function can only be called by OGN token contract.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"staker\":\"Address of the account that is creating the stake\"}},\"totalCurrentHoldings(address)\":{\"details\":\"Calculate all current holdings of a user: staked value + prorated rewards\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalExpectedRewards(address)\":{\"details\":\"Calculate all the rewards a user can expect to receive.\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalStaked(address)\":{\"details\":\"Calculate all the staked value a user has put into the contract, rewards not included\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"transferGovernance(address)\":{\"details\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\",\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/staking/SingleAssetStaking.sol\":\"SingleAssetStaking\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x640b6dee7a4b830bdfd52b5031a07fc2b12209f5b2e29e5d364a7d37f69d8076\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\\n * the optional functions; to access them see {ERC20Detailed}.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xe5bb0f57cff3e299f360052ba50f1ea0fff046df2be070b6943e0e3c3fdad8a9\"},\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"../../math/SafeMath.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require((value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \\\"SafeERC20: decreased allowance below zero\\\");\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) { // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6f2c9955d65c522b80f4b8792f076512d2df947d2112cbc4d98a4781ed42ede2\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"pragma solidity ^0.5.5;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following \\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { codehash := extcodehash(account) }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1a8e5072509c5ea7365eb1d48030b9be865140c8fb779968da0a459a0e174a11\"},\"@openzeppelin/upgrades/contracts/Initializable.sol\":{\"content\":\"pragma solidity >=0.4.24 <0.7.0;\\n\\n\\n/**\\n * @title Initializable\\n *\\n * @dev Helper contract to support initializer functions. To use it, replace\\n * the constructor with a function that has the `initializer` modifier.\\n * WARNING: Unlike constructors, initializer functions must be manually\\n * invoked. This applies both to deploying an Initializable contract, as well\\n * as extending an Initializable contract via inheritance.\\n * WARNING: When used with inheritance, manual care must be taken to not invoke\\n * a parent initializer twice, or ensure that all initializers are idempotent,\\n * because this is not dealt with automatically as with constructors.\\n */\\ncontract Initializable {\\n\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to use in the initializer function of a contract.\\n */\\n modifier initializer() {\\n require(initializing || isConstructor() || !initialized, \\\"Contract instance has already been initialized\\\");\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n /// @dev Returns true if and only if the function is running in the constructor\\n function isConstructor() private view returns (bool) {\\n // extcodesize checks the size of the code stored in an address, and\\n // address returns the current address. Since the code is still not\\n // deployed when running a constructor, any checks on its code size will\\n // yield zero, making it an effective way to detect if a contract is\\n // under construction or not.\\n address self = address(this);\\n uint256 cs;\\n assembly { cs := extcodesize(self) }\\n return cs == 0;\\n }\\n\\n // Reserved storage space to allow for layout changes in the future.\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x9bfec92e36234ecc99b5d37230acb6cd1f99560233753162204104a4897e8721\"},\"contracts/governance/Governable.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\n/**\\n * @title OUSD Governable Contract\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32\\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32\\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32\\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() internal {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0x3e51ea48102945bf4b305bf9722a07514a585a29555d92f8c84352d1a4cfcee1\"},\"contracts/staking/SingleAssetStaking.sol\":{\"content\":\"pragma solidity 0.5.11;\\npragma experimental ABIEncoderV2;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\nimport {\\n Initializable\\n} from \\\"@openzeppelin/upgrades/contracts/Initializable.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\ncontract SingleAssetStaking is Initializable, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n /* ========== STATE VARIABLES ========== */\\n\\n IERC20 public stakingToken; // this is both the staking and rewards\\n\\n struct Stake {\\n uint256 amount; // amount to stake\\n uint256 end; // when does the staking period end\\n uint256 duration; // the duration of the stake\\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\\n bool paid;\\n uint8 stakeType;\\n }\\n\\n struct DropRoot {\\n bytes32 hash;\\n uint256 depth;\\n }\\n\\n uint256[] public durations; // allowed durations\\n uint256[] public rates; // rates that correspond with the allowed durations\\n\\n uint256 public totalOutstanding;\\n bool public paused;\\n\\n mapping(address => Stake[]) public userStakes;\\n\\n mapping(uint8 => DropRoot) public dropRoots;\\n\\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\\n uint8 constant USER_STAKE_TYPE = 0;\\n uint256 constant MAX_STAKES = 256;\\n\\n /* ========== Initialize ========== */\\n\\n /**\\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\\n * for preApproved contracts can only be called once\\n * @param _stakingToken Address of the token that we are staking\\n * @param _durations Array of allowed durations in seconds\\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\\n * durations in 1e18 precision\\n */\\n function initialize(\\n address _stakingToken,\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor initializer {\\n stakingToken = IERC20(_stakingToken);\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /* ========= Internal helper functions ======== */\\n\\n /**\\n * @dev Validate and set the duration and corresponding rates, will emit\\n * events NewRate and NewDurations\\n */\\n function _setDurationRates(\\n uint256[] memory _durations,\\n uint256[] memory _rates\\n ) internal {\\n require(\\n _rates.length == _durations.length,\\n \\\"Mismatch durations and rates\\\"\\n );\\n\\n for (uint256 i = 0; i < _rates.length; i++) {\\n require(_rates[i] < uint240(-1), \\\"Max rate exceeded\\\");\\n }\\n\\n rates = _rates;\\n durations = _durations;\\n\\n emit NewRates(msg.sender, rates);\\n emit NewDurations(msg.sender, durations);\\n }\\n\\n function _totalExpectedRewards(Stake[] storage stakes)\\n internal\\n view\\n returns (uint256 total)\\n {\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (!stake.paid) {\\n total = total.add(stake.amount.mulTruncate(stake.rate));\\n }\\n }\\n }\\n\\n function _totalExpected(Stake storage _stake)\\n internal\\n view\\n returns (uint256)\\n {\\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\\n }\\n\\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\\n internal\\n view\\n returns (bool)\\n {\\n Stake[] storage stakes = userStakes[account];\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (stakes[i].stakeType == stakeType) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n function _findDurationRate(uint256 duration)\\n internal\\n view\\n returns (uint240)\\n {\\n for (uint256 i = 0; i < durations.length; i++) {\\n if (duration == durations[i]) {\\n return uint240(rates[i]);\\n }\\n }\\n return 0;\\n }\\n\\n /**\\n * @dev Internal staking function\\n * will insert the stake into the stakes array and verify we have\\n * enough to pay off stake + reward\\n * @param staker Address of the staker\\n * @param stakeType Number that represent the type of the stake, 0 is user\\n * initiated all else is currently preApproved\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\\n * to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n */\\n function _stake(\\n address staker,\\n uint8 stakeType,\\n uint256 duration,\\n uint240 rate,\\n uint256 amount\\n ) internal {\\n require(!paused, \\\"Staking paused\\\");\\n\\n Stake[] storage stakes = userStakes[staker];\\n\\n uint256 end = block.timestamp.add(duration);\\n\\n uint256 i = stakes.length; // start at the end of the current array\\n\\n require(i < MAX_STAKES, \\\"Max stakes\\\");\\n\\n stakes.length += 1; // grow the array\\n // find the spot where we can insert the current stake\\n // this should make an increasing list sorted by end\\n while (i != 0 && stakes[i - 1].end > end) {\\n // shift it back one\\n stakes[i] = stakes[i - 1];\\n i -= 1;\\n }\\n\\n // insert the stake\\n Stake storage newStake = stakes[i];\\n newStake.rate = rate;\\n newStake.stakeType = stakeType;\\n newStake.end = end;\\n newStake.duration = duration;\\n newStake.amount = amount;\\n\\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\\n\\n emit Staked(staker, amount);\\n }\\n\\n function _stakeWithChecks(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) internal {\\n require(amount > 0, \\\"Cannot stake 0\\\");\\n\\n uint240 rewardRate = _findDurationRate(duration);\\n require(rewardRate > 0, \\\"Invalid duration\\\"); // we couldn't find the rate that correspond to the passed duration\\n\\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\\n // transfer in the token so that we can stake the correct amount\\n stakingToken.safeTransferFrom(staker, address(this), amount);\\n }\\n\\n modifier requireLiquidity() {\\n // we need to have enough balance to cover the rewards after the operation is complete\\n _;\\n require(\\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\\n \\\"Insufficient rewards\\\"\\n );\\n }\\n\\n /* ========== VIEWS ========== */\\n\\n function getAllDurations() external view returns (uint256[] memory) {\\n return durations;\\n }\\n\\n function getAllRates() external view returns (uint256[] memory) {\\n return rates;\\n }\\n\\n /**\\n * @dev Return all the stakes paid and unpaid for a given user\\n * @param account Address of the account that we want to look up\\n */\\n function getAllStakes(address account)\\n external\\n view\\n returns (Stake[] memory)\\n {\\n return userStakes[account];\\n }\\n\\n /**\\n * @dev Find the rate that corresponds to a given duration\\n * @param _duration Number of seconds\\n */\\n function durationRewardRate(uint256 _duration)\\n external\\n view\\n returns (uint256)\\n {\\n return _findDurationRate(_duration);\\n }\\n\\n /**\\n * @dev Has the airdropped stake already been claimed\\n */\\n function airDroppedStakeClaimed(address account, uint8 stakeType)\\n external\\n view\\n returns (bool)\\n {\\n return _airDroppedStakeClaimed(account, stakeType);\\n }\\n\\n /**\\n * @dev Calculate all the staked value a user has put into the contract,\\n * rewards not included\\n * @param account Address of the account that we want to look up\\n */\\n function totalStaked(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (!stakes[i].paid) {\\n total = total.add(stakes[i].amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Calculate all the rewards a user can expect to receive.\\n * @param account Address of the account that we want to look up\\n */\\n function totalExpectedRewards(address account)\\n external\\n view\\n returns (uint256)\\n {\\n return _totalExpectedRewards(userStakes[account]);\\n }\\n\\n /**\\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\\n * @param account Address of the account that we want to look up\\n */\\n function totalCurrentHoldings(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (stake.paid) {\\n continue;\\n } else if (stake.end < block.timestamp) {\\n total = total.add(_totalExpected(stake));\\n } else {\\n //calcualte the precentage accrued in term of rewards\\n total = total.add(\\n stake.amount.add(\\n stake.amount.mulTruncate(stake.rate).mulTruncate(\\n stake\\n .duration\\n .sub(stake.end.sub(block.timestamp))\\n .divPrecisely(stake.duration)\\n )\\n )\\n );\\n }\\n }\\n }\\n\\n /* ========== MUTATIVE FUNCTIONS ========== */\\n\\n /**\\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\\n * an airdrop or a compensation program.\\n * Only 1 of each type is allowed per user. The proof must match the root hash\\n * @param index Number that is zero base index of the stake in the payout entry\\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param merkleProof Array of proofs for that amount\\n */\\n function airDroppedStake(\\n uint256 index,\\n uint8 stakeType,\\n uint256 duration,\\n uint256 rate,\\n uint256 amount,\\n bytes32[] calldata merkleProof\\n ) external requireLiquidity {\\n require(stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n require(rate < uint240(-1), \\\"Max rate exceeded\\\");\\n require(index < 2**merkleProof.length, \\\"Invalid index\\\");\\n DropRoot storage dropRoot = dropRoots[stakeType];\\n require(merkleProof.length == dropRoot.depth, \\\"Invalid proof\\\");\\n\\n // Compute the merkle root\\n bytes32 node = keccak256(\\n abi.encodePacked(\\n index,\\n stakeType,\\n address(this),\\n msg.sender,\\n duration,\\n rate,\\n amount\\n )\\n );\\n uint256 path = index;\\n for (uint16 i = 0; i < merkleProof.length; i++) {\\n if ((path & 0x01) == 1) {\\n node = keccak256(abi.encodePacked(merkleProof[i], node));\\n } else {\\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\\n }\\n path /= 2;\\n }\\n\\n // Check the merkle proof\\n require(node == dropRoot.hash, \\\"Stake not approved\\\");\\n\\n // verify that we haven't already staked\\n require(\\n !_airDroppedStakeClaimed(msg.sender, stakeType),\\n \\\"Already staked\\\"\\n );\\n\\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract.\\n * User must have already approved the contract for specified amount.\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\\n // no checks are performed in this function since those are already present in _stakeWithChecks\\n _stakeWithChecks(msg.sender, amount, duration);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract. This function\\n * can only be called by OGN token contract.\\n * @param staker Address of the account that is creating the stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stakeWithSender(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) external returns (bool) {\\n require(\\n msg.sender == address(stakingToken),\\n \\\"Only token contract can make this call\\\"\\n );\\n\\n _stakeWithChecks(staker, amount, duration);\\n return true;\\n }\\n\\n /**\\n * @dev Exit out of all possible stakes\\n */\\n function exit() external requireLiquidity {\\n Stake[] storage stakes = userStakes[msg.sender];\\n require(stakes.length > 0, \\\"Nothing staked\\\");\\n\\n uint256 totalWithdraw = 0;\\n uint256 l = stakes.length;\\n do {\\n Stake storage exitStake = stakes[l - 1];\\n // stop on the first ended stake that's already been paid\\n if (exitStake.end < block.timestamp && exitStake.paid) {\\n break;\\n }\\n //might not be ended\\n if (exitStake.end < block.timestamp) {\\n //we are paying out the stake\\n exitStake.paid = true;\\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\\n }\\n l--;\\n } while (l > 0);\\n require(totalWithdraw > 0, \\\"All stakes in lock-up\\\");\\n\\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\\n emit Withdrawn(msg.sender, totalWithdraw);\\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\\n }\\n\\n /* ========== MODIFIERS ========== */\\n\\n function setPaused(bool _paused) external onlyGovernor {\\n paused = _paused;\\n emit Paused(msg.sender, paused);\\n }\\n\\n /**\\n * @dev Set new durations and rates will not effect existing stakes\\n * @param _durations Array of durations in seconds\\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\\n */\\n function setDurationRates(\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor {\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /**\\n * @dev Set air drop root for a specific stake type\\n * @param _stakeType Type of staking must be greater than 0\\n * @param _rootHash Root hash of the Merkle Tree\\n * @param _proofDepth Depth of the Merklke Tree\\n */\\n function setAirDropRoot(\\n uint8 _stakeType,\\n bytes32 _rootHash,\\n uint256 _proofDepth\\n ) external onlyGovernor {\\n require(_stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n dropRoots[_stakeType].hash = _rootHash;\\n dropRoots[_stakeType].depth = _proofDepth;\\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\\n }\\n\\n /* ========== EVENTS ========== */\\n\\n event Staked(address indexed user, uint256 amount);\\n event Withdrawn(address indexed user, uint256 amount);\\n event Paused(address indexed user, bool yes);\\n event NewDurations(address indexed user, uint256[] durations);\\n event NewRates(address indexed user, uint256[] rates);\\n event NewAirDropRootHash(\\n uint8 stakeType,\\n bytes32 rootHash,\\n uint256 proofDepth\\n );\\n}\\n\",\"keccak256\":\"0xc6efc99f88cb18fb16135e61b60d5b5b2afa061003c665cbc91b4bed635bae51\"},\"contracts/utils/StableMath.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\\n */\\n function scaleBy(uint256 x, int8 adjustment)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (adjustment > 0) {\\n x = x.mul(10**uint256(adjustment));\\n } else if (adjustment < 0) {\\n x = x.div(10**uint256(adjustment * -1));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e38 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0xa77fccf850feb6d54ba3a6530f92554caef8a67a1ceb573d4f8a5d1bf64ff9d2\"}},\"version\":1}", - "bytecode": "0x608060405262000018336001600160e01b036200007116565b6200002b6001600160e01b036200008416565b6001600160a01b031660006001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a362000098565b60008051602062002c7283398151915255565b60008051602062002c728339815191525490565b612bca80620000a86000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c4e565b6103c5565b6040516101ce919061280d565b60405180910390f35b6101df610487565b6040516101ce91906127bc565b6101f4610497565b6040516101ce91906129fb565b61021461020f366004611e1a565b61049d565b005b610214610224366004611daa565b610519565b610214610237366004611f74565b6105b0565b61021461024a366004611eb1565b610650565b6102576108db565b6040516101ce9190612840565b6102146108e4565b61025761027a366004611d2d565b610927565b61028761096a565b6040516101ce919061285c565b6102146102a2366004611e92565b610979565b6101f46102b5366004611e56565b610a29565b6101f46102c8366004611c4e565b610a43565b6101f46102db366004611c4e565b610b62565b6102576102ee366004611d7a565b610bec565b610306610301366004611cf3565b610c01565b6040516101ce96959493929190612a09565b6101f4610326366004611e56565b610c63565b610333610c81565b6040516101ce919061281e565b610257610cd9565b610214610356366004611c4e565b610cfc565b6101f4610369366004611e56565b610d73565b61038161037c366004611f56565b610d80565b6040516101ce92919061284e565b61021461039d366004611c6c565b610d99565b610214610eca565b6101f46103b8366004611c4e565b6110c0565b6103336110e1565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611137565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128cb565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612840565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128cb565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061115c92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128cb565b60ff83166105f45760405162461bcd60e51b81526004016104c19061288b565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612a63565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c19061288b565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c19061290b565b600281900a87106106b95760405162461bcd60e51b81526004016104c1906128db565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129ab565b6000888830338a8a8a60405160200161070d9796959493929190612741565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c92919061270f565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b292919061270f565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129cb565b610804338a61127f565b156108215760405162461bcd60e51b81526004016104c19061296b565b61082e338a8a8a8a6112f4565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127bc565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e74565b10156108d25760405162461bcd60e51b81526004016104c19061299b565b50505050505050565b60375460ff1681565b6108ec61153d565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c1906129db565b61092533611562565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c1906128eb565b61095f8484846115db565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115db565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127bc565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e74565b1015610a255760405162461bcd60e51b81526004016104c19061299b565b5050565b6000610a348261165d565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116bb565b859063ffffffff6116e116565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461170690919063ffffffff16565b60028801549063ffffffff61170616565b9063ffffffff61174816565b60038501548554610b34916001600160f01b031663ffffffff61177d16565b9063ffffffff61177d16565b83549063ffffffff6116e116565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116e116565b92505b600101610b7c565b6000610bf8838361127f565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611137565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128cb565b610d2981611792565b806001600160a01b0316610d3b611137565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128cb565b600054610100900460ff1680610dd65750610dd66117b6565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c19061298b565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061115c92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c19061297b565b80546000905b6000836001830381548110610f0e57fe5b90600052602060002090600402019050428160010154108015610f3c57506003810154600160f01b900460ff165b15610f475750610f8f565b4281600101541015610f845760038101805460ff60f01b1916600160f01b179055610f81610f74826116bb565b849063ffffffff6116e116565b92505b506000190180610efd575b60008211610faf5760405162461bcd60e51b81526004016104c19061294b565b603654610fc2908363ffffffff61170616565b60365560405133907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590610ff79085906129fb565b60405180910390a260335461101c906001600160a01b0316338463ffffffff6117bc16565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906110529030906004016127bc565b60206040518083038186803b15801561106a57600080fd5b505afa15801561107e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110a29190810190611e74565b10156109255760405162461bcd60e51b81526004016104c19061299b565b6001600160a01b0381166000908152603860205260408120610bfb9061181a565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461117d5760405162461bcd60e51b81526004016104c19061291b565b60005b81518110156111ce576000196001600160f01b03168282815181106111a157fe5b6020026020010151106111c65760405162461bcd60e51b81526004016104c19061290b565b600101611180565b5080516111e2906035906020840190611b04565b5081516111f6906034906020850190611b04565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c36035604051611231919061282f565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d46034604051611273919061282f565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112e9578360ff168282815481106112b257fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112e157600192505050610bfb565b600101611299565b506000949350505050565b60375460ff16156113175760405162461bcd60e51b81526004016104c19061293b565b6001600160a01b038516600090815260386020526040812090611340428663ffffffff6116e116565b825490915061010081106113665760405162461bcd60e51b81526004016104c19061287b565b82546001016113758482611b4f565b505b80158015906113a557508183600183038154811061139157fe5b906000526020600020906004020160010154115b1561146f578260018203815481106113b957fe5b90600052602060002090600402018382815481106113d357fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611377565b600083828154811061147d57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114ec6114dd826116bb565b6036549063ffffffff6116e116565b6036556040516001600160a01b038a16907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9061152a9088906129fb565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b0381166115885760405162461bcd60e51b81526004016104c19061292b565b806001600160a01b031661159a611137565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115d881611891565b50565b600082116115fb5760405162461bcd60e51b81526004016104c1906128ab565b60006116068261165d565b90506000816001600160f01b0316116116315760405162461bcd60e51b81526004016104c19061289b565b61163f8460008484876112f4565b6033546105aa906001600160a01b031685308663ffffffff6118b516565b6000805b6034548110156116b2576034818154811061167857fe5b90600052602060002001548314156116aa576035818154811061169757fe5b9060005260206000200154915050610482565b600101611661565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61177d16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128bb565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118d9565b60008061176384670de0b6b3a764000063ffffffff61190516565b9050611775818463ffffffff61193f16565b949350505050565b6000610bf88383670de0b6b3a7640000611981565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161181590849063a9059cbb60e01b906117de90869086906024016127f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119af565b505050565b6000805b825481101561188b57600083828154811061183557fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff16611882576003810154815461187f91610f7491906001600160f01b031663ffffffff61177d16565b92505b5060010161181e565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117de908790879087906024016127ca565b600081848411156118fd5760405162461bcd60e51b81526004016104c1919061286a565b505050900390565b60008261191457506000610bfb565b8282028284828161192157fe5b0414610bf85760405162461bcd60e51b81526004016104c19061295b565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611a94565b600080611994858563ffffffff61190516565b90506119a6818463ffffffff61193f16565b95945050505050565b6119c1826001600160a01b0316611acb565b6119dd5760405162461bcd60e51b81526004016104c1906129eb565b60006060836001600160a01b0316836040516119f99190612735565b6000604051808303816000865af19150503d8060008114611a36576040519150601f19603f3d011682016040523d82523d6000602084013e611a3b565b606091505b509150915081611a5d5760405162461bcd60e51b81526004016104c1906128fb565b8051156105aa5780806020019051611a789190810190611e38565b6105aa5760405162461bcd60e51b81526004016104c1906129bb565b60008183611ab55760405162461bcd60e51b81526004016104c1919061286a565b506000838581611ac157fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611775575050151592915050565b828054828255906000526020600020908101928215611b3f579160200282015b82811115611b3f578251825591602001919060010190611b24565b50611b4b929150611b7b565b5090565b815481835581811115611815576004028160040283600052602060002091820191016118159190611b95565b61049491905b80821115611b4b5760008155600101611b81565b61049491905b80821115611b4b57600080825560018201819055600282018190556003820155600401611b9b565b8035610bfb81612b58565b60008083601f840112611be057600080fd5b50813567ffffffffffffffff811115611bf857600080fd5b602083019150836020820283011115611c1057600080fd5b9250929050565b8035610bfb81612b6c565b8051610bfb81612b6c565b8035610bfb81612b75565b8051610bfb81612b75565b8035610bfb81612b7e565b600060208284031215611c6057600080fd5b60006117758484611bc3565b600080600080600060608688031215611c8457600080fd5b6000611c908888611bc3565b955050602086013567ffffffffffffffff811115611cad57600080fd5b611cb988828901611bce565b9450945050604086013567ffffffffffffffff811115611cd857600080fd5b611ce488828901611bce565b92509250509295509295909350565b60008060408385031215611d0657600080fd5b6000611d128585611bc3565b9250506020611d2385828601611c2d565b9150509250929050565b600080600060608486031215611d4257600080fd5b6000611d4e8686611bc3565b9350506020611d5f86828701611c2d565b9250506040611d7086828701611c2d565b9150509250925092565b60008060408385031215611d8d57600080fd5b6000611d998585611bc3565b9250506020611d2385828601611c43565b60008060008060408587031215611dc057600080fd5b843567ffffffffffffffff811115611dd757600080fd5b611de387828801611bce565b9450945050602085013567ffffffffffffffff811115611e0257600080fd5b611e0e87828801611bce565b95989497509550505050565b600060208284031215611e2c57600080fd5b60006117758484611c17565b600060208284031215611e4a57600080fd5b60006117758484611c22565b600060208284031215611e6857600080fd5b60006117758484611c2d565b600060208284031215611e8657600080fd5b60006117758484611c38565b60008060408385031215611ea557600080fd5b6000611d128585611c2d565b600080600080600080600060c0888a031215611ecc57600080fd5b6000611ed88a8a611c2d565b9750506020611ee98a828b01611c43565b9650506040611efa8a828b01611c2d565b9550506060611f0b8a828b01611c2d565b9450506080611f1c8a828b01611c2d565b93505060a088013567ffffffffffffffff811115611f3957600080fd5b611f458a828b01611bce565b925092505092959891949750929550565b600060208284031215611f6857600080fd5b60006117758484611c43565b600080600060608486031215611f8957600080fd5b6000611d4e8686611c43565b6000611fa1838361267c565b505060c00190565b6000611fb583836120e2565b505060200190565b611fce611fc982612aa7565b612b1a565b82525050565b611fce81612aa7565b6000611fe882612a90565b611ff28185612a9e565b9350611ffd83612a7e565b8060005b8381101561202b5781516120158882611f95565b975061202083612a7e565b925050600101612001565b509495945050505050565b600061204182612a90565b61204b8185612a9e565b935061205683612a7e565b8060005b8381101561202b57815161206e8882611fa9565b975061207983612a7e565b92505060010161205a565b600061208f82612a94565b6120998185612a9e565b93506120a483612a84565b8060005b8381101561202b576120b982612b36565b6120c38882611fa9565b97506120ce83612a98565b9250506001016120a8565b611fce81612ab2565b611fce81610494565b611fce6120f782610494565b610494565b600061210782612a90565b6121118185610482565b9350612121818560208601612ae0565b9290920192915050565b611fce81612ad5565b600061213f82612a90565b6121498185612a9e565b9350612159818560208601612ae0565b61216281612b42565b9093019392505050565b6000612179600a83612a9e565b694d6178207374616b657360b01b815260200192915050565b600061219f601883612a9e565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121d8601083612a9e565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612204600e83612a9e565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061222e601b83612a9e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612267601a83612a9e565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122a0600d83612a9e565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122c9602683612a9e565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612311602083612a9e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061234a601183612a9e565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612377601c83612a9e565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123b0601a83612a9e565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b60006123e9600e83612a9e565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612413601583612a9e565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612444602183612a9e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612487600e83612a9e565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124b1600e83612a9e565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124db602e83612a9e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061252b601483612a9e565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061255b600d83612a9e565b6c24b73b30b634b210383937b7b360991b815260200192915050565b6000612584602a83612a9e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125d0601283612a9e565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b60006125fe603083612a9e565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b6000612650601f83612a9e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c083019061268d84826120e2565b5060208201516126a060208501826120e2565b5060408201516126b360408501826120e2565b5060608201516126c660608501826126ec565b5060808201516126d960808501826120d9565b5060a08201516105aa60a08501826126f5565b611fce81612ac3565b611fce81612acf565b611fce61270a82612acf565b612b2b565b600061271b82856120eb565b60208201915061272b82846120eb565b5060200192915050565b600061096382846120fc565b600061274d828a6120eb565b60208201915061275d82896126fe565b60018201915061276d8288611fbd565b60148201915061277d8287611fbd565b60148201915061278d82866120eb565b60208201915061279d82856120eb565b6020820191506127ad82846120eb565b50602001979650505050505050565b60208101610bfb8284611fd4565b606081016127d88286611fd4565b6127e56020830185611fd4565b61177560408301846120e2565b604081016128008285611fd4565b61096360208301846120e2565b60208082528101610bf88184611fdd565b60208082528101610bf88184612036565b60208082528101610bf88184612084565b60208101610bfb82846120d9565b6040810161280082856120e2565b60208101610bfb828461212b565b60208082528101610bf88184612134565b60208082528101610bfb8161216c565b60208082528101610bfb81612192565b60208082528101610bfb816121cb565b60208082528101610bfb816121f7565b60208082528101610bfb81612221565b60208082528101610bfb8161225a565b60208082528101610bfb81612293565b60208082528101610bfb816122bc565b60208082528101610bfb81612304565b60208082528101610bfb8161233d565b60208082528101610bfb8161236a565b60208082528101610bfb816123a3565b60208082528101610bfb816123dc565b60208082528101610bfb81612406565b60208082528101610bfb81612437565b60208082528101610bfb8161247a565b60208082528101610bfb816124a4565b60208082528101610bfb816124ce565b60208082528101610bfb8161251e565b60208082528101610bfb8161254e565b60208082528101610bfb81612577565b60208082528101610bfb816125c3565b60208082528101610bfb816125f1565b60208082528101610bfb81612643565b60208101610bfb82846120e2565b60c08101612a1782896120e2565b612a2460208301886120e2565b612a3160408301876120e2565b612a3e60608301866126ec565b612a4b60808301856120d9565b612a5860a08301846126f5565b979650505050505050565b60608101612a7182866126f5565b6127e560208301856120e2565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612ab7565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612aa7565b60005b83811015612afb578181015183820152602001612ae3565b838111156105aa5750506000910152565b6000610bfb6120f783610494565b6000610bfb826000610bfb82612b52565b6000610bfb82612b4c565b6000610bfb8254612b0c565b601f01601f191690565b60f81b90565b60601b90565b612b6181612aa7565b81146115d857600080fd5b612b6181612ab2565b612b6181610494565b612b6181612acf56fea365627a7a723158203b8a45a1f9626792470b52e91b20e9152e303efcdb1c49cbfeeff74029c015c96c6578706572696d656e74616cf564736f6c634300050b00407bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c4e565b6103c5565b6040516101ce919061280d565b60405180910390f35b6101df610487565b6040516101ce91906127bc565b6101f4610497565b6040516101ce91906129fb565b61021461020f366004611e1a565b61049d565b005b610214610224366004611daa565b610519565b610214610237366004611f74565b6105b0565b61021461024a366004611eb1565b610650565b6102576108db565b6040516101ce9190612840565b6102146108e4565b61025761027a366004611d2d565b610927565b61028761096a565b6040516101ce919061285c565b6102146102a2366004611e92565b610979565b6101f46102b5366004611e56565b610a29565b6101f46102c8366004611c4e565b610a43565b6101f46102db366004611c4e565b610b62565b6102576102ee366004611d7a565b610bec565b610306610301366004611cf3565b610c01565b6040516101ce96959493929190612a09565b6101f4610326366004611e56565b610c63565b610333610c81565b6040516101ce919061281e565b610257610cd9565b610214610356366004611c4e565b610cfc565b6101f4610369366004611e56565b610d73565b61038161037c366004611f56565b610d80565b6040516101ce92919061284e565b61021461039d366004611c6c565b610d99565b610214610eca565b6101f46103b8366004611c4e565b6110c0565b6103336110e1565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611137565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128cb565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612840565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128cb565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061115c92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128cb565b60ff83166105f45760405162461bcd60e51b81526004016104c19061288b565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612a63565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c19061288b565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c19061290b565b600281900a87106106b95760405162461bcd60e51b81526004016104c1906128db565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129ab565b6000888830338a8a8a60405160200161070d9796959493929190612741565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c92919061270f565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b292919061270f565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129cb565b610804338a61127f565b156108215760405162461bcd60e51b81526004016104c19061296b565b61082e338a8a8a8a6112f4565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127bc565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e74565b10156108d25760405162461bcd60e51b81526004016104c19061299b565b50505050505050565b60375460ff1681565b6108ec61153d565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c1906129db565b61092533611562565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c1906128eb565b61095f8484846115db565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115db565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127bc565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e74565b1015610a255760405162461bcd60e51b81526004016104c19061299b565b5050565b6000610a348261165d565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116bb565b859063ffffffff6116e116565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461170690919063ffffffff16565b60028801549063ffffffff61170616565b9063ffffffff61174816565b60038501548554610b34916001600160f01b031663ffffffff61177d16565b9063ffffffff61177d16565b83549063ffffffff6116e116565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116e116565b92505b600101610b7c565b6000610bf8838361127f565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611137565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128cb565b610d2981611792565b806001600160a01b0316610d3b611137565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128cb565b600054610100900460ff1680610dd65750610dd66117b6565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c19061298b565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061115c92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c19061297b565b80546000905b6000836001830381548110610f0e57fe5b90600052602060002090600402019050428160010154108015610f3c57506003810154600160f01b900460ff165b15610f475750610f8f565b4281600101541015610f845760038101805460ff60f01b1916600160f01b179055610f81610f74826116bb565b849063ffffffff6116e116565b92505b506000190180610efd575b60008211610faf5760405162461bcd60e51b81526004016104c19061294b565b603654610fc2908363ffffffff61170616565b60365560405133907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d590610ff79085906129fb565b60405180910390a260335461101c906001600160a01b0316338463ffffffff6117bc16565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906110529030906004016127bc565b60206040518083038186803b15801561106a57600080fd5b505afa15801561107e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110a29190810190611e74565b10156109255760405162461bcd60e51b81526004016104c19061299b565b6001600160a01b0381166000908152603860205260408120610bfb9061181a565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461117d5760405162461bcd60e51b81526004016104c19061291b565b60005b81518110156111ce576000196001600160f01b03168282815181106111a157fe5b6020026020010151106111c65760405162461bcd60e51b81526004016104c19061290b565b600101611180565b5080516111e2906035906020840190611b04565b5081516111f6906034906020850190611b04565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c36035604051611231919061282f565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d46034604051611273919061282f565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112e9578360ff168282815481106112b257fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112e157600192505050610bfb565b600101611299565b506000949350505050565b60375460ff16156113175760405162461bcd60e51b81526004016104c19061293b565b6001600160a01b038516600090815260386020526040812090611340428663ffffffff6116e116565b825490915061010081106113665760405162461bcd60e51b81526004016104c19061287b565b82546001016113758482611b4f565b505b80158015906113a557508183600183038154811061139157fe5b906000526020600020906004020160010154115b1561146f578260018203815481106113b957fe5b90600052602060002090600402018382815481106113d357fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611377565b600083828154811061147d57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114ec6114dd826116bb565b6036549063ffffffff6116e116565b6036556040516001600160a01b038a16907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9061152a9088906129fb565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b0381166115885760405162461bcd60e51b81526004016104c19061292b565b806001600160a01b031661159a611137565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115d881611891565b50565b600082116115fb5760405162461bcd60e51b81526004016104c1906128ab565b60006116068261165d565b90506000816001600160f01b0316116116315760405162461bcd60e51b81526004016104c19061289b565b61163f8460008484876112f4565b6033546105aa906001600160a01b031685308663ffffffff6118b516565b6000805b6034548110156116b2576034818154811061167857fe5b90600052602060002001548314156116aa576035818154811061169757fe5b9060005260206000200154915050610482565b600101611661565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61177d16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128bb565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118d9565b60008061176384670de0b6b3a764000063ffffffff61190516565b9050611775818463ffffffff61193f16565b949350505050565b6000610bf88383670de0b6b3a7640000611981565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161181590849063a9059cbb60e01b906117de90869086906024016127f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119af565b505050565b6000805b825481101561188b57600083828154811061183557fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff16611882576003810154815461187f91610f7491906001600160f01b031663ffffffff61177d16565b92505b5060010161181e565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117de908790879087906024016127ca565b600081848411156118fd5760405162461bcd60e51b81526004016104c1919061286a565b505050900390565b60008261191457506000610bfb565b8282028284828161192157fe5b0414610bf85760405162461bcd60e51b81526004016104c19061295b565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611a94565b600080611994858563ffffffff61190516565b90506119a6818463ffffffff61193f16565b95945050505050565b6119c1826001600160a01b0316611acb565b6119dd5760405162461bcd60e51b81526004016104c1906129eb565b60006060836001600160a01b0316836040516119f99190612735565b6000604051808303816000865af19150503d8060008114611a36576040519150601f19603f3d011682016040523d82523d6000602084013e611a3b565b606091505b509150915081611a5d5760405162461bcd60e51b81526004016104c1906128fb565b8051156105aa5780806020019051611a789190810190611e38565b6105aa5760405162461bcd60e51b81526004016104c1906129bb565b60008183611ab55760405162461bcd60e51b81526004016104c1919061286a565b506000838581611ac157fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611775575050151592915050565b828054828255906000526020600020908101928215611b3f579160200282015b82811115611b3f578251825591602001919060010190611b24565b50611b4b929150611b7b565b5090565b815481835581811115611815576004028160040283600052602060002091820191016118159190611b95565b61049491905b80821115611b4b5760008155600101611b81565b61049491905b80821115611b4b57600080825560018201819055600282018190556003820155600401611b9b565b8035610bfb81612b58565b60008083601f840112611be057600080fd5b50813567ffffffffffffffff811115611bf857600080fd5b602083019150836020820283011115611c1057600080fd5b9250929050565b8035610bfb81612b6c565b8051610bfb81612b6c565b8035610bfb81612b75565b8051610bfb81612b75565b8035610bfb81612b7e565b600060208284031215611c6057600080fd5b60006117758484611bc3565b600080600080600060608688031215611c8457600080fd5b6000611c908888611bc3565b955050602086013567ffffffffffffffff811115611cad57600080fd5b611cb988828901611bce565b9450945050604086013567ffffffffffffffff811115611cd857600080fd5b611ce488828901611bce565b92509250509295509295909350565b60008060408385031215611d0657600080fd5b6000611d128585611bc3565b9250506020611d2385828601611c2d565b9150509250929050565b600080600060608486031215611d4257600080fd5b6000611d4e8686611bc3565b9350506020611d5f86828701611c2d565b9250506040611d7086828701611c2d565b9150509250925092565b60008060408385031215611d8d57600080fd5b6000611d998585611bc3565b9250506020611d2385828601611c43565b60008060008060408587031215611dc057600080fd5b843567ffffffffffffffff811115611dd757600080fd5b611de387828801611bce565b9450945050602085013567ffffffffffffffff811115611e0257600080fd5b611e0e87828801611bce565b95989497509550505050565b600060208284031215611e2c57600080fd5b60006117758484611c17565b600060208284031215611e4a57600080fd5b60006117758484611c22565b600060208284031215611e6857600080fd5b60006117758484611c2d565b600060208284031215611e8657600080fd5b60006117758484611c38565b60008060408385031215611ea557600080fd5b6000611d128585611c2d565b600080600080600080600060c0888a031215611ecc57600080fd5b6000611ed88a8a611c2d565b9750506020611ee98a828b01611c43565b9650506040611efa8a828b01611c2d565b9550506060611f0b8a828b01611c2d565b9450506080611f1c8a828b01611c2d565b93505060a088013567ffffffffffffffff811115611f3957600080fd5b611f458a828b01611bce565b925092505092959891949750929550565b600060208284031215611f6857600080fd5b60006117758484611c43565b600080600060608486031215611f8957600080fd5b6000611d4e8686611c43565b6000611fa1838361267c565b505060c00190565b6000611fb583836120e2565b505060200190565b611fce611fc982612aa7565b612b1a565b82525050565b611fce81612aa7565b6000611fe882612a90565b611ff28185612a9e565b9350611ffd83612a7e565b8060005b8381101561202b5781516120158882611f95565b975061202083612a7e565b925050600101612001565b509495945050505050565b600061204182612a90565b61204b8185612a9e565b935061205683612a7e565b8060005b8381101561202b57815161206e8882611fa9565b975061207983612a7e565b92505060010161205a565b600061208f82612a94565b6120998185612a9e565b93506120a483612a84565b8060005b8381101561202b576120b982612b36565b6120c38882611fa9565b97506120ce83612a98565b9250506001016120a8565b611fce81612ab2565b611fce81610494565b611fce6120f782610494565b610494565b600061210782612a90565b6121118185610482565b9350612121818560208601612ae0565b9290920192915050565b611fce81612ad5565b600061213f82612a90565b6121498185612a9e565b9350612159818560208601612ae0565b61216281612b42565b9093019392505050565b6000612179600a83612a9e565b694d6178207374616b657360b01b815260200192915050565b600061219f601883612a9e565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121d8601083612a9e565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612204600e83612a9e565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061222e601b83612a9e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612267601a83612a9e565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122a0600d83612a9e565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122c9602683612a9e565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612311602083612a9e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061234a601183612a9e565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612377601c83612a9e565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123b0601a83612a9e565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b60006123e9600e83612a9e565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612413601583612a9e565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612444602183612a9e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612487600e83612a9e565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124b1600e83612a9e565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124db602e83612a9e565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061252b601483612a9e565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061255b600d83612a9e565b6c24b73b30b634b210383937b7b360991b815260200192915050565b6000612584602a83612a9e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125d0601283612a9e565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b60006125fe603083612a9e565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b6000612650601f83612a9e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c083019061268d84826120e2565b5060208201516126a060208501826120e2565b5060408201516126b360408501826120e2565b5060608201516126c660608501826126ec565b5060808201516126d960808501826120d9565b5060a08201516105aa60a08501826126f5565b611fce81612ac3565b611fce81612acf565b611fce61270a82612acf565b612b2b565b600061271b82856120eb565b60208201915061272b82846120eb565b5060200192915050565b600061096382846120fc565b600061274d828a6120eb565b60208201915061275d82896126fe565b60018201915061276d8288611fbd565b60148201915061277d8287611fbd565b60148201915061278d82866120eb565b60208201915061279d82856120eb565b6020820191506127ad82846120eb565b50602001979650505050505050565b60208101610bfb8284611fd4565b606081016127d88286611fd4565b6127e56020830185611fd4565b61177560408301846120e2565b604081016128008285611fd4565b61096360208301846120e2565b60208082528101610bf88184611fdd565b60208082528101610bf88184612036565b60208082528101610bf88184612084565b60208101610bfb82846120d9565b6040810161280082856120e2565b60208101610bfb828461212b565b60208082528101610bf88184612134565b60208082528101610bfb8161216c565b60208082528101610bfb81612192565b60208082528101610bfb816121cb565b60208082528101610bfb816121f7565b60208082528101610bfb81612221565b60208082528101610bfb8161225a565b60208082528101610bfb81612293565b60208082528101610bfb816122bc565b60208082528101610bfb81612304565b60208082528101610bfb8161233d565b60208082528101610bfb8161236a565b60208082528101610bfb816123a3565b60208082528101610bfb816123dc565b60208082528101610bfb81612406565b60208082528101610bfb81612437565b60208082528101610bfb8161247a565b60208082528101610bfb816124a4565b60208082528101610bfb816124ce565b60208082528101610bfb8161251e565b60208082528101610bfb8161254e565b60208082528101610bfb81612577565b60208082528101610bfb816125c3565b60208082528101610bfb816125f1565b60208082528101610bfb81612643565b60208101610bfb82846120e2565b60c08101612a1782896120e2565b612a2460208301886120e2565b612a3160408301876120e2565b612a3e60608301866126ec565b612a4b60808301856120d9565b612a5860a08301846126f5565b979650505050505050565b60608101612a7182866126f5565b6127e560208301856120e2565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612ab7565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612aa7565b60005b83811015612afb578181015183820152602001612ae3565b838111156105aa5750506000910152565b6000610bfb6120f783610494565b6000610bfb826000610bfb82612b52565b6000610bfb82612b4c565b6000610bfb8254612b0c565b601f01601f191690565b60f81b90565b60601b90565b612b6181612aa7565b81146115d857600080fd5b612b6181612ab2565b612b6181610494565b612b6181612acf56fea365627a7a723158203b8a45a1f9626792470b52e91b20e9152e303efcdb1c49cbfeeff74029c015c96c6578706572696d656e74616cf564736f6c634300050b0040", + "solcInputHash": "c7459e40fa663addef2a13f82ab72194", + "metadata": "{\"compiler\":{\"version\":\"0.5.11+commit.22be8592.mod\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAllStakes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"internalType\":\"struct SingleAssetStaking.Stake[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalOutstanding\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"setDurationRates\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_stakeType\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_rootHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_proofDepth\",\"type\":\"uint256\"}],\"name\":\"setAirDropRoot\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"merkleProof\",\"type\":\"bytes32[]\"}],\"name\":\"airDroppedStake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stakeWithSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"stakingToken\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"}],\"name\":\"stake\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"durationRewardRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalCurrentHoldings\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalStaked\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"name\":\"airDroppedStakeClaimed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint240\",\"name\":\"rate\",\"type\":\"uint240\"},{\"internalType\":\"bool\",\"name\":\"paid\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"durations\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllDurations\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"rates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"dropRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingToken\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_durations\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_rates\",\"type\":\"uint256[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"totalExpectedRewards\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAllRates\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rate\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"yes\",\"type\":\"bool\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"durations\",\"type\":\"uint256[]\"}],\"name\":\"NewDurations\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"rates\",\"type\":\"uint256[]\"}],\"name\":\"NewRates\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"stakeType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"rootHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"proofDepth\",\"type\":\"uint256\"}],\"name\":\"NewAirDropRootHash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"PendingGovernorshipTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorshipTransferred\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])\":{\"details\":\"Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from an airdrop or a compensation program. Only 1 of each type is allowed per user. The proof must match the root hash\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"index\":\"Number that is zero base index of the stake in the payout entry\",\"merkleProof\":\"Array of proofs for that amount\",\"rate\":\"Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\",\"stakeType\":\"Number that represent the type of the stake, must not be 0 which is user stake\"}},\"airDroppedStakeClaimed(address,uint8)\":{\"details\":\"Has the airdropped stake already been claimed\"},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"durationRewardRate(uint256)\":{\"details\":\"Find the rate that corresponds to a given duration\",\"params\":{\"_duration\":\"Number of seconds\"}},\"exit()\":{\"details\":\"Exit out of all possible stakes\"},\"getAllStakes(address)\":{\"details\":\"Return all the stakes paid and unpaid for a given user\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,uint256[],uint256[])\":{\"details\":\"Initialize the contracts, sets up durations, rates, and preApprover for preApproved contracts can only be called once\",\"params\":{\"_durations\":\"Array of allowed durations in seconds\",\"_rates\":\"Array of rates(0.3 is 30%) that correspond to the allowed durations in 1e18 precision\",\"_stakingToken\":\"Address of the token that we are staking\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"setAirDropRoot(uint8,bytes32,uint256)\":{\"details\":\"Set air drop root for a specific stake type\",\"params\":{\"_proofDepth\":\"Depth of the Merklke Tree\",\"_rootHash\":\"Root hash of the Merkle Tree\",\"_stakeType\":\"Type of staking must be greater than 0\"}},\"setDurationRates(uint256[],uint256[])\":{\"details\":\"Set new durations and rates will not effect existing stakes\",\"params\":{\"_durations\":\"Array of durations in seconds\",\"_rates\":\"Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\"}},\"stake(uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. User must have already approved the contract for specified amount.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\"}},\"stakeWithSender(address,uint256,uint256)\":{\"details\":\"Stake an approved amount of staking token into the contract. This function can only be called by OGN token contract.\",\"params\":{\"amount\":\"Number of tokens to stake in 1e18\",\"duration\":\"Number of seconds this stake will be held for\",\"staker\":\"Address of the account that is creating the stake\"}},\"totalCurrentHoldings(address)\":{\"details\":\"Calculate all current holdings of a user: staked value + prorated rewards\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalExpectedRewards(address)\":{\"details\":\"Calculate all the rewards a user can expect to receive.\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"totalStaked(address)\":{\"details\":\"Calculate all the staked value a user has put into the contract, rewards not included\",\"params\":{\"account\":\"Address of the account that we want to look up\"}},\"transferGovernance(address)\":{\"details\":\"Transfers Governance of the contract to a new account (`newGovernor`). Can only be called by the current Governor. Must be claimed for this to complete\",\"params\":{\"_newGovernor\":\"Address of the new Governor\"}}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/staking/SingleAssetStaking.sol\":\"SingleAssetStaking\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x640b6dee7a4b830bdfd52b5031a07fc2b12209f5b2e29e5d364a7d37f69d8076\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\\n * the optional functions; to access them see {ERC20Detailed}.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xe5bb0f57cff3e299f360052ba50f1ea0fff046df2be070b6943e0e3c3fdad8a9\"},\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"../../math/SafeMath.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require((value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \\\"SafeERC20: decreased allowance below zero\\\");\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) { // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6f2c9955d65c522b80f4b8792f076512d2df947d2112cbc4d98a4781ed42ede2\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"pragma solidity ^0.5.5;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following \\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { codehash := extcodehash(account) }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x1a8e5072509c5ea7365eb1d48030b9be865140c8fb779968da0a459a0e174a11\"},\"@openzeppelin/upgrades/contracts/Initializable.sol\":{\"content\":\"pragma solidity >=0.4.24 <0.7.0;\\n\\n\\n/**\\n * @title Initializable\\n *\\n * @dev Helper contract to support initializer functions. To use it, replace\\n * the constructor with a function that has the `initializer` modifier.\\n * WARNING: Unlike constructors, initializer functions must be manually\\n * invoked. This applies both to deploying an Initializable contract, as well\\n * as extending an Initializable contract via inheritance.\\n * WARNING: When used with inheritance, manual care must be taken to not invoke\\n * a parent initializer twice, or ensure that all initializers are idempotent,\\n * because this is not dealt with automatically as with constructors.\\n */\\ncontract Initializable {\\n\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n bool private initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private initializing;\\n\\n /**\\n * @dev Modifier to use in the initializer function of a contract.\\n */\\n modifier initializer() {\\n require(initializing || isConstructor() || !initialized, \\\"Contract instance has already been initialized\\\");\\n\\n bool isTopLevelCall = !initializing;\\n if (isTopLevelCall) {\\n initializing = true;\\n initialized = true;\\n }\\n\\n _;\\n\\n if (isTopLevelCall) {\\n initializing = false;\\n }\\n }\\n\\n /// @dev Returns true if and only if the function is running in the constructor\\n function isConstructor() private view returns (bool) {\\n // extcodesize checks the size of the code stored in an address, and\\n // address returns the current address. Since the code is still not\\n // deployed when running a constructor, any checks on its code size will\\n // yield zero, making it an effective way to detect if a contract is\\n // under construction or not.\\n address self = address(this);\\n uint256 cs;\\n assembly { cs := extcodesize(self) }\\n return cs == 0;\\n }\\n\\n // Reserved storage space to allow for layout changes in the future.\\n uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0x9bfec92e36234ecc99b5d37230acb6cd1f99560233753162204104a4897e8721\"},\"contracts/governance/Governable.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\n/**\\n * @title OUSD Governable Contract\\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\\n * from owner to governor and renounce methods removed. Does not use\\n * Context.sol like Ownable.sol does for simplification.\\n * @author Origin Protocol Inc\\n */\\ncontract Governable {\\n // Storage position of the owner and pendingOwner of the contract\\n // keccak256(\\\"OUSD.governor\\\");\\n bytes32\\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32\\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32\\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\\n\\n // See OpenZeppelin ReentrancyGuard implementation\\n uint256 constant _NOT_ENTERED = 1;\\n uint256 constant _ENTERED = 2;\\n\\n event PendingGovernorshipTransfer(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n event GovernorshipTransferred(\\n address indexed previousGovernor,\\n address indexed newGovernor\\n );\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial Governor.\\n */\\n constructor() internal {\\n _setGovernor(msg.sender);\\n emit GovernorshipTransferred(address(0), _governor());\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function governor() public view returns (address) {\\n return _governor();\\n }\\n\\n /**\\n * @dev Returns the address of the current Governor.\\n */\\n function _governor() internal view returns (address governorOut) {\\n bytes32 position = governorPosition;\\n assembly {\\n governorOut := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Returns the address of the pending Governor.\\n */\\n function _pendingGovernor()\\n internal\\n view\\n returns (address pendingGovernor)\\n {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n pendingGovernor := sload(position)\\n }\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the Governor.\\n */\\n modifier onlyGovernor() {\\n require(isGovernor(), \\\"Caller is not the Governor\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current Governor.\\n */\\n function isGovernor() public view returns (bool) {\\n return msg.sender == _governor();\\n }\\n\\n function _setGovernor(address newGovernor) internal {\\n bytes32 position = governorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and make it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n bytes32 position = reentryStatusPosition;\\n uint256 _reentry_status;\\n assembly {\\n _reentry_status := sload(position)\\n }\\n\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_reentry_status != _ENTERED, \\\"Reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n assembly {\\n sstore(position, _ENTERED)\\n }\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n assembly {\\n sstore(position, _NOT_ENTERED)\\n }\\n }\\n\\n function _setPendingGovernor(address newGovernor) internal {\\n bytes32 position = pendingGovernorPosition;\\n assembly {\\n sstore(position, newGovernor)\\n }\\n }\\n\\n /**\\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the current Governor. Must be claimed for this to complete\\n * @param _newGovernor Address of the new Governor\\n */\\n function transferGovernance(address _newGovernor) external onlyGovernor {\\n _setPendingGovernor(_newGovernor);\\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\\n }\\n\\n /**\\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\\n * Can only be called by the new Governor.\\n */\\n function claimGovernance() external {\\n require(\\n msg.sender == _pendingGovernor(),\\n \\\"Only the pending Governor can complete the claim\\\"\\n );\\n _changeGovernor(msg.sender);\\n }\\n\\n /**\\n * @dev Change Governance of the contract to a new account (`newGovernor`).\\n * @param _newGovernor Address of the new Governor\\n */\\n function _changeGovernor(address _newGovernor) internal {\\n require(_newGovernor != address(0), \\\"New Governor is address(0)\\\");\\n emit GovernorshipTransferred(_governor(), _newGovernor);\\n _setGovernor(_newGovernor);\\n }\\n}\\n\",\"keccak256\":\"0x3e51ea48102945bf4b305bf9722a07514a585a29555d92f8c84352d1a4cfcee1\"},\"contracts/staking/SingleAssetStaking.sol\":{\"content\":\"pragma solidity 0.5.11;\\npragma experimental ABIEncoderV2;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\nimport {\\n Initializable\\n} from \\\"@openzeppelin/upgrades/contracts/Initializable.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\n\\ncontract SingleAssetStaking is Initializable, Governable {\\n using SafeMath for uint256;\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n /* ========== STATE VARIABLES ========== */\\n\\n IERC20 public stakingToken; // this is both the staking and rewards\\n\\n struct Stake {\\n uint256 amount; // amount to stake\\n uint256 end; // when does the staking period end\\n uint256 duration; // the duration of the stake\\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\\n bool paid;\\n uint8 stakeType;\\n }\\n\\n struct DropRoot {\\n bytes32 hash;\\n uint256 depth;\\n }\\n\\n uint256[] public durations; // allowed durations\\n uint256[] public rates; // rates that correspond with the allowed durations\\n\\n uint256 public totalOutstanding;\\n bool public paused;\\n\\n mapping(address => Stake[]) public userStakes;\\n\\n mapping(uint8 => DropRoot) public dropRoots;\\n\\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\\n uint8 constant USER_STAKE_TYPE = 0;\\n uint256 constant MAX_STAKES = 256;\\n\\n /* ========== Initialize ========== */\\n\\n /**\\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\\n * for preApproved contracts can only be called once\\n * @param _stakingToken Address of the token that we are staking\\n * @param _durations Array of allowed durations in seconds\\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\\n * durations in 1e18 precision\\n */\\n function initialize(\\n address _stakingToken,\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor initializer {\\n stakingToken = IERC20(_stakingToken);\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /* ========= Internal helper functions ======== */\\n\\n /**\\n * @dev Validate and set the duration and corresponding rates, will emit\\n * events NewRate and NewDurations\\n */\\n function _setDurationRates(\\n uint256[] memory _durations,\\n uint256[] memory _rates\\n ) internal {\\n require(\\n _rates.length == _durations.length,\\n \\\"Mismatch durations and rates\\\"\\n );\\n\\n for (uint256 i = 0; i < _rates.length; i++) {\\n require(_rates[i] < uint240(-1), \\\"Max rate exceeded\\\");\\n }\\n\\n rates = _rates;\\n durations = _durations;\\n\\n emit NewRates(msg.sender, rates);\\n emit NewDurations(msg.sender, durations);\\n }\\n\\n function _totalExpectedRewards(Stake[] storage stakes)\\n internal\\n view\\n returns (uint256 total)\\n {\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (!stake.paid) {\\n total = total.add(stake.amount.mulTruncate(stake.rate));\\n }\\n }\\n }\\n\\n function _totalExpected(Stake storage _stake)\\n internal\\n view\\n returns (uint256)\\n {\\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\\n }\\n\\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\\n internal\\n view\\n returns (bool)\\n {\\n Stake[] storage stakes = userStakes[account];\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (stakes[i].stakeType == stakeType) {\\n return true;\\n }\\n }\\n return false;\\n }\\n\\n function _findDurationRate(uint256 duration)\\n internal\\n view\\n returns (uint240)\\n {\\n for (uint256 i = 0; i < durations.length; i++) {\\n if (duration == durations[i]) {\\n return uint240(rates[i]);\\n }\\n }\\n return 0;\\n }\\n\\n /**\\n * @dev Internal staking function\\n * will insert the stake into the stakes array and verify we have\\n * enough to pay off stake + reward\\n * @param staker Address of the staker\\n * @param stakeType Number that represent the type of the stake, 0 is user\\n * initiated all else is currently preApproved\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\\n * to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n */\\n function _stake(\\n address staker,\\n uint8 stakeType,\\n uint256 duration,\\n uint240 rate,\\n uint256 amount\\n ) internal {\\n require(!paused, \\\"Staking paused\\\");\\n\\n Stake[] storage stakes = userStakes[staker];\\n\\n uint256 end = block.timestamp.add(duration);\\n\\n uint256 i = stakes.length; // start at the end of the current array\\n\\n require(i < MAX_STAKES, \\\"Max stakes\\\");\\n\\n stakes.length += 1; // grow the array\\n // find the spot where we can insert the current stake\\n // this should make an increasing list sorted by end\\n while (i != 0 && stakes[i - 1].end > end) {\\n // shift it back one\\n stakes[i] = stakes[i - 1];\\n i -= 1;\\n }\\n\\n // insert the stake\\n Stake storage newStake = stakes[i];\\n newStake.rate = rate;\\n newStake.stakeType = stakeType;\\n newStake.end = end;\\n newStake.duration = duration;\\n newStake.amount = amount;\\n\\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\\n\\n emit Staked(staker, amount, duration, rate);\\n }\\n\\n function _stakeWithChecks(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) internal {\\n require(amount > 0, \\\"Cannot stake 0\\\");\\n\\n uint240 rewardRate = _findDurationRate(duration);\\n require(rewardRate > 0, \\\"Invalid duration\\\"); // we couldn't find the rate that correspond to the passed duration\\n\\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\\n // transfer in the token so that we can stake the correct amount\\n stakingToken.safeTransferFrom(staker, address(this), amount);\\n }\\n\\n modifier requireLiquidity() {\\n // we need to have enough balance to cover the rewards after the operation is complete\\n _;\\n require(\\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\\n \\\"Insufficient rewards\\\"\\n );\\n }\\n\\n /* ========== VIEWS ========== */\\n\\n function getAllDurations() external view returns (uint256[] memory) {\\n return durations;\\n }\\n\\n function getAllRates() external view returns (uint256[] memory) {\\n return rates;\\n }\\n\\n /**\\n * @dev Return all the stakes paid and unpaid for a given user\\n * @param account Address of the account that we want to look up\\n */\\n function getAllStakes(address account)\\n external\\n view\\n returns (Stake[] memory)\\n {\\n return userStakes[account];\\n }\\n\\n /**\\n * @dev Find the rate that corresponds to a given duration\\n * @param _duration Number of seconds\\n */\\n function durationRewardRate(uint256 _duration)\\n external\\n view\\n returns (uint256)\\n {\\n return _findDurationRate(_duration);\\n }\\n\\n /**\\n * @dev Has the airdropped stake already been claimed\\n */\\n function airDroppedStakeClaimed(address account, uint8 stakeType)\\n external\\n view\\n returns (bool)\\n {\\n return _airDroppedStakeClaimed(account, stakeType);\\n }\\n\\n /**\\n * @dev Calculate all the staked value a user has put into the contract,\\n * rewards not included\\n * @param account Address of the account that we want to look up\\n */\\n function totalStaked(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n if (!stakes[i].paid) {\\n total = total.add(stakes[i].amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Calculate all the rewards a user can expect to receive.\\n * @param account Address of the account that we want to look up\\n */\\n function totalExpectedRewards(address account)\\n external\\n view\\n returns (uint256)\\n {\\n return _totalExpectedRewards(userStakes[account]);\\n }\\n\\n /**\\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\\n * @param account Address of the account that we want to look up\\n */\\n function totalCurrentHoldings(address account)\\n external\\n view\\n returns (uint256 total)\\n {\\n Stake[] storage stakes = userStakes[account];\\n\\n for (uint256 i = 0; i < stakes.length; i++) {\\n Stake storage stake = stakes[i];\\n if (stake.paid) {\\n continue;\\n } else if (stake.end < block.timestamp) {\\n total = total.add(_totalExpected(stake));\\n } else {\\n //calcualte the precentage accrued in term of rewards\\n total = total.add(\\n stake.amount.add(\\n stake.amount.mulTruncate(stake.rate).mulTruncate(\\n stake\\n .duration\\n .sub(stake.end.sub(block.timestamp))\\n .divPrecisely(stake.duration)\\n )\\n )\\n );\\n }\\n }\\n }\\n\\n /* ========== MUTATIVE FUNCTIONS ========== */\\n\\n /**\\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\\n * an airdrop or a compensation program.\\n * Only 1 of each type is allowed per user. The proof must match the root hash\\n * @param index Number that is zero base index of the stake in the payout entry\\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\\n * @param duration Number of seconds this stake will be held for\\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param merkleProof Array of proofs for that amount\\n */\\n function airDroppedStake(\\n uint256 index,\\n uint8 stakeType,\\n uint256 duration,\\n uint256 rate,\\n uint256 amount,\\n bytes32[] calldata merkleProof\\n ) external requireLiquidity {\\n require(stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n require(rate < uint240(-1), \\\"Max rate exceeded\\\");\\n require(index < 2**merkleProof.length, \\\"Invalid index\\\");\\n DropRoot storage dropRoot = dropRoots[stakeType];\\n require(merkleProof.length == dropRoot.depth, \\\"Invalid proof\\\");\\n\\n // Compute the merkle root\\n bytes32 node = keccak256(\\n abi.encodePacked(\\n index,\\n stakeType,\\n address(this),\\n msg.sender,\\n duration,\\n rate,\\n amount\\n )\\n );\\n uint256 path = index;\\n for (uint16 i = 0; i < merkleProof.length; i++) {\\n if ((path & 0x01) == 1) {\\n node = keccak256(abi.encodePacked(merkleProof[i], node));\\n } else {\\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\\n }\\n path /= 2;\\n }\\n\\n // Check the merkle proof\\n require(node == dropRoot.hash, \\\"Stake not approved\\\");\\n\\n // verify that we haven't already staked\\n require(\\n !_airDroppedStakeClaimed(msg.sender, stakeType),\\n \\\"Already staked\\\"\\n );\\n\\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract.\\n * User must have already approved the contract for specified amount.\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\\n // no checks are performed in this function since those are already present in _stakeWithChecks\\n _stakeWithChecks(msg.sender, amount, duration);\\n }\\n\\n /**\\n * @dev Stake an approved amount of staking token into the contract. This function\\n * can only be called by OGN token contract.\\n * @param staker Address of the account that is creating the stake\\n * @param amount Number of tokens to stake in 1e18\\n * @param duration Number of seconds this stake will be held for\\n */\\n function stakeWithSender(\\n address staker,\\n uint256 amount,\\n uint256 duration\\n ) external returns (bool) {\\n require(\\n msg.sender == address(stakingToken),\\n \\\"Only token contract can make this call\\\"\\n );\\n\\n _stakeWithChecks(staker, amount, duration);\\n return true;\\n }\\n\\n /**\\n * @dev Exit out of all possible stakes\\n */\\n function exit() external requireLiquidity {\\n Stake[] storage stakes = userStakes[msg.sender];\\n require(stakes.length > 0, \\\"Nothing staked\\\");\\n\\n uint256 totalWithdraw = 0;\\n uint256 stakedAmount = 0;\\n uint256 l = stakes.length;\\n do {\\n Stake storage exitStake = stakes[l - 1];\\n // stop on the first ended stake that's already been paid\\n if (exitStake.end < block.timestamp && exitStake.paid) {\\n break;\\n }\\n //might not be ended\\n if (exitStake.end < block.timestamp) {\\n //we are paying out the stake\\n exitStake.paid = true;\\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\\n stakedAmount = stakedAmount.add(exitStake.amount);\\n }\\n l--;\\n } while (l > 0);\\n require(totalWithdraw > 0, \\\"All stakes in lock-up\\\");\\n\\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\\n }\\n\\n /* ========== MODIFIERS ========== */\\n\\n function setPaused(bool _paused) external onlyGovernor {\\n paused = _paused;\\n emit Paused(msg.sender, paused);\\n }\\n\\n /**\\n * @dev Set new durations and rates will not effect existing stakes\\n * @param _durations Array of durations in seconds\\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\\n */\\n function setDurationRates(\\n uint256[] calldata _durations,\\n uint256[] calldata _rates\\n ) external onlyGovernor {\\n _setDurationRates(_durations, _rates);\\n }\\n\\n /**\\n * @dev Set air drop root for a specific stake type\\n * @param _stakeType Type of staking must be greater than 0\\n * @param _rootHash Root hash of the Merkle Tree\\n * @param _proofDepth Depth of the Merklke Tree\\n */\\n function setAirDropRoot(\\n uint8 _stakeType,\\n bytes32 _rootHash,\\n uint256 _proofDepth\\n ) external onlyGovernor {\\n require(_stakeType != USER_STAKE_TYPE, \\\"Cannot be normal staking\\\");\\n dropRoots[_stakeType].hash = _rootHash;\\n dropRoots[_stakeType].depth = _proofDepth;\\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\\n }\\n\\n /* ========== EVENTS ========== */\\n\\n event Staked(\\n address indexed user,\\n uint256 amount,\\n uint256 duration,\\n uint256 rate\\n );\\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\\n event Paused(address indexed user, bool yes);\\n event NewDurations(address indexed user, uint256[] durations);\\n event NewRates(address indexed user, uint256[] rates);\\n event NewAirDropRootHash(\\n uint8 stakeType,\\n bytes32 rootHash,\\n uint256 proofDepth\\n );\\n}\\n\",\"keccak256\":\"0x397ead290428160d0e34a9d74a54d68498d8ad12d8329c3b576b0fcacae17b2e\"},\"contracts/utils/StableMath.sol\":{\"content\":\"pragma solidity 0.5.11;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/math/SafeMath.sol\\\";\\n\\n// Based on StableMath from Stability Labs Pty. Ltd.\\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\\n\\nlibrary StableMath {\\n using SafeMath for uint256;\\n\\n /**\\n * @dev Scaling unit for use in specific calculations,\\n * where 1 * 10**18, or 1e18 represents a unit '1'\\n */\\n uint256 private constant FULL_SCALE = 1e18;\\n\\n /***************************************\\n Helpers\\n ****************************************/\\n\\n /**\\n * @dev Adjust the scale of an integer\\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\\n */\\n function scaleBy(uint256 x, int8 adjustment)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (adjustment > 0) {\\n x = x.mul(10**uint256(adjustment));\\n } else if (adjustment < 0) {\\n x = x.div(10**uint256(adjustment * -1));\\n }\\n return x;\\n }\\n\\n /***************************************\\n Precise Arithmetic\\n ****************************************/\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulTruncateScale(x, y, FULL_SCALE);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @param scale Scale unit\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit\\n */\\n function mulTruncateScale(\\n uint256 x,\\n uint256 y,\\n uint256 scale\\n ) internal pure returns (uint256) {\\n // e.g. assume scale = fullScale\\n // z = 10e18 * 9e17 = 9e36\\n uint256 z = x.mul(y);\\n // return 9e38 / 1e18 = 9e18\\n return z.div(scale);\\n }\\n\\n /**\\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\\n * @param x Left hand input to multiplication\\n * @param y Right hand input to multiplication\\n * @return Result after multiplying the two inputs and then dividing by the shared\\n * scale unit, rounded up to the closest base unit.\\n */\\n function mulTruncateCeil(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e17 * 17268172638 = 138145381104e17\\n uint256 scaled = x.mul(y);\\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\\n return ceil.div(FULL_SCALE);\\n }\\n\\n /**\\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\\n * @param x Left hand input to division\\n * @param y Right hand input to division\\n * @return Result after multiplying the left operand by the scale, and\\n * executing the division on the right hand input.\\n */\\n function divPrecisely(uint256 x, uint256 y)\\n internal\\n pure\\n returns (uint256)\\n {\\n // e.g. 8e18 * 1e18 = 8e36\\n uint256 z = x.mul(FULL_SCALE);\\n // e.g. 8e36 / 10e18 = 8e17\\n return z.div(y);\\n }\\n}\\n\",\"keccak256\":\"0xa77fccf850feb6d54ba3a6530f92554caef8a67a1ceb573d4f8a5d1bf64ff9d2\"}},\"version\":1}", + "bytecode": "0x608060405262000018336001600160e01b036200007116565b6200002b6001600160e01b036200008416565b6001600160a01b031660006001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a362000098565b60008051602062002ccd83398151915255565b60008051602062002ccd8339815191525490565b612c2580620000a86000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c6d565b6103c5565b6040516101ce9190612835565b60405180910390f35b6101df610487565b6040516101ce91906127e4565b6101f4610497565b6040516101ce9190612a23565b61021461020f366004611e39565b61049d565b005b610214610224366004611dc9565b610519565b610214610237366004611f93565b6105b0565b61021461024a366004611ed0565b610650565b6102576108db565b6040516101ce9190612868565b6102146108e4565b61025761027a366004611d4c565b610927565b61028761096a565b6040516101ce9190612884565b6102146102a2366004611eb1565b610979565b6101f46102b5366004611e75565b610a29565b6101f46102c8366004611c6d565b610a43565b6101f46102db366004611c6d565b610b62565b6102576102ee366004611d99565b610bec565b610306610301366004611d12565b610c01565b6040516101ce96959493929190612a59565b6101f4610326366004611e75565b610c63565b610333610c81565b6040516101ce9190612846565b610257610cd9565b610214610356366004611c6d565b610cfc565b6101f4610369366004611e75565b610d73565b61038161037c366004611f75565b610d80565b6040516101ce929190612876565b61021461039d366004611c8b565b610d99565b610214610eca565b6101f46103b8366004611c6d565b6110ce565b6103336110ef565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611145565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128f3565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612868565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128f3565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061116a92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128f3565b60ff83166105f45760405162461bcd60e51b81526004016104c1906128b3565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612ab3565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c1906128b3565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c190612933565b600281900a87106106b95760405162461bcd60e51b81526004016104c190612903565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129d3565b6000888830338a8a8a60405160200161070d9796959493929190612769565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c929190612737565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b2929190612737565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129f3565b610804338a61128d565b156108215760405162461bcd60e51b81526004016104c190612993565b61082e338a8a8a8a611302565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127e4565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e93565b10156108d25760405162461bcd60e51b81526004016104c1906129c3565b50505050505050565b60375460ff1681565b6108ec61154f565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c190612a03565b61092533611574565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c190612913565b61095f8484846115ed565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115ed565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127e4565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e93565b1015610a255760405162461bcd60e51b81526004016104c1906129c3565b5050565b6000610a348261166f565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116cd565b859063ffffffff6116f316565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461171890919063ffffffff16565b60028801549063ffffffff61171816565b9063ffffffff61175a16565b60038501548554610b34916001600160f01b031663ffffffff61178f16565b9063ffffffff61178f16565b83549063ffffffff6116f316565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116f316565b92505b600101610b7c565b6000610bf8838361128d565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611145565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128f3565b610d29816117a4565b806001600160a01b0316610d3b611145565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128f3565b600054610100900460ff1680610dd65750610dd66117c8565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c1906129b3565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061116a92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c1906129a3565b805460009081905b6000846001830381548110610f1057fe5b90600052602060002090600402019050428160010154108015610f3e57506003810154600160f01b900460ff165b15610f495750610f9a565b4281600101541015610f8f5760038101805460ff60f01b1916600160f01b179055610f76610ab9826116cd565b8154909450610f8c90849063ffffffff6116f316565b92505b506000190180610eff575b60008311610fba5760405162461bcd60e51b81526004016104c190612973565b603654610fcd908463ffffffff61171816565b60365560405133907f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6906110049086908690612876565b60405180910390a2603354611029906001600160a01b0316338563ffffffff6117ce16565b50506036546033546040516370a0823160e01b81529193506001600160a01b031691506370a08231906110609030906004016127e4565b60206040518083038186803b15801561107857600080fd5b505afa15801561108c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110b09190810190611e93565b10156109255760405162461bcd60e51b81526004016104c1906129c3565b6001600160a01b0381166000908152603860205260408120610bfb9061182c565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461118b5760405162461bcd60e51b81526004016104c190612943565b60005b81518110156111dc576000196001600160f01b03168282815181106111af57fe5b6020026020010151106111d45760405162461bcd60e51b81526004016104c190612933565b60010161118e565b5080516111f0906035906020840190611b23565b508151611204906034906020850190611b23565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c3603560405161123f9190612857565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d460346040516112819190612857565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112f7578360ff168282815481106112c057fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112ef57600192505050610bfb565b6001016112a7565b506000949350505050565b60375460ff16156113255760405162461bcd60e51b81526004016104c190612963565b6001600160a01b03851660009081526038602052604081209061134e428663ffffffff6116f316565b825490915061010081106113745760405162461bcd60e51b81526004016104c1906128a3565b82546001016113838482611b6e565b505b80158015906113b357508183600183038154811061139f57fe5b906000526020600020906004020160010154115b1561147d578260018203815481106113c757fe5b90600052602060002090600402018382815481106113e157fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611385565b600083828154811061148b57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114fa6114eb826116cd565b6036549063ffffffff6116f316565b6036556040516001600160a01b038a16907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9061153c9088908b908b90612a31565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b03811661159a5760405162461bcd60e51b81526004016104c190612953565b806001600160a01b03166115ac611145565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115ea816118b0565b50565b6000821161160d5760405162461bcd60e51b81526004016104c1906128d3565b60006116188261166f565b90506000816001600160f01b0316116116435760405162461bcd60e51b81526004016104c1906128c3565b611651846000848487611302565b6033546105aa906001600160a01b031685308663ffffffff6118d416565b6000805b6034548110156116c4576034818154811061168a57fe5b90600052602060002001548314156116bc57603581815481106116a957fe5b9060005260206000200154915050610482565b600101611673565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61178f16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128e3565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118f8565b60008061177584670de0b6b3a764000063ffffffff61192416565b9050611787818463ffffffff61195e16565b949350505050565b6000610bf88383670de0b6b3a76400006119a0565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161182790849063a9059cbb60e01b906117f0908690869060240161281a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119ce565b505050565b6000805b82548110156118aa57600083828154811061184757fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff166118a1576003810154815461189e9161189191906001600160f01b031663ffffffff61178f16565b849063ffffffff6116f316565b92505b50600101611830565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117f0908790879087906024016127f2565b6000818484111561191c5760405162461bcd60e51b81526004016104c19190612892565b505050900390565b60008261193357506000610bfb565b8282028284828161194057fe5b0414610bf85760405162461bcd60e51b81526004016104c190612983565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611ab3565b6000806119b3858563ffffffff61192416565b90506119c5818463ffffffff61195e16565b95945050505050565b6119e0826001600160a01b0316611aea565b6119fc5760405162461bcd60e51b81526004016104c190612a13565b60006060836001600160a01b031683604051611a18919061275d565b6000604051808303816000865af19150503d8060008114611a55576040519150601f19603f3d011682016040523d82523d6000602084013e611a5a565b606091505b509150915081611a7c5760405162461bcd60e51b81526004016104c190612923565b8051156105aa5780806020019051611a979190810190611e57565b6105aa5760405162461bcd60e51b81526004016104c1906129e3565b60008183611ad45760405162461bcd60e51b81526004016104c19190612892565b506000838581611ae057fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611787575050151592915050565b828054828255906000526020600020908101928215611b5e579160200282015b82811115611b5e578251825591602001919060010190611b43565b50611b6a929150611b9a565b5090565b815481835581811115611827576004028160040283600052602060002091820191016118279190611bb4565b61049491905b80821115611b6a5760008155600101611ba0565b61049491905b80821115611b6a57600080825560018201819055600282018190556003820155600401611bba565b8035610bfb81612bb3565b60008083601f840112611bff57600080fd5b50813567ffffffffffffffff811115611c1757600080fd5b602083019150836020820283011115611c2f57600080fd5b9250929050565b8035610bfb81612bc7565b8051610bfb81612bc7565b8035610bfb81612bd0565b8051610bfb81612bd0565b8035610bfb81612bd9565b600060208284031215611c7f57600080fd5b60006117878484611be2565b600080600080600060608688031215611ca357600080fd5b6000611caf8888611be2565b955050602086013567ffffffffffffffff811115611ccc57600080fd5b611cd888828901611bed565b9450945050604086013567ffffffffffffffff811115611cf757600080fd5b611d0388828901611bed565b92509250509295509295909350565b60008060408385031215611d2557600080fd5b6000611d318585611be2565b9250506020611d4285828601611c4c565b9150509250929050565b600080600060608486031215611d6157600080fd5b6000611d6d8686611be2565b9350506020611d7e86828701611c4c565b9250506040611d8f86828701611c4c565b9150509250925092565b60008060408385031215611dac57600080fd5b6000611db88585611be2565b9250506020611d4285828601611c62565b60008060008060408587031215611ddf57600080fd5b843567ffffffffffffffff811115611df657600080fd5b611e0287828801611bed565b9450945050602085013567ffffffffffffffff811115611e2157600080fd5b611e2d87828801611bed565b95989497509550505050565b600060208284031215611e4b57600080fd5b60006117878484611c36565b600060208284031215611e6957600080fd5b60006117878484611c41565b600060208284031215611e8757600080fd5b60006117878484611c4c565b600060208284031215611ea557600080fd5b60006117878484611c57565b60008060408385031215611ec457600080fd5b6000611d318585611c4c565b600080600080600080600060c0888a031215611eeb57600080fd5b6000611ef78a8a611c4c565b9750506020611f088a828b01611c62565b9650506040611f198a828b01611c4c565b9550506060611f2a8a828b01611c4c565b9450506080611f3b8a828b01611c4c565b93505060a088013567ffffffffffffffff811115611f5857600080fd5b611f648a828b01611bed565b925092505092959891949750929550565b600060208284031215611f8757600080fd5b60006117878484611c62565b600080600060608486031215611fa857600080fd5b6000611d6d8686611c62565b6000611fc0838361269b565b505060c00190565b6000611fd48383612101565b505060200190565b611fed611fe882612af7565b612b75565b82525050565b611fed81612af7565b600061200782612ae0565b6120118185612aee565b935061201c83612ace565b8060005b8381101561204a5781516120348882611fb4565b975061203f83612ace565b925050600101612020565b509495945050505050565b600061206082612ae0565b61206a8185612aee565b935061207583612ace565b8060005b8381101561204a57815161208d8882611fc8565b975061209883612ace565b925050600101612079565b60006120ae82612ae4565b6120b88185612aee565b93506120c383612ad4565b8060005b8381101561204a576120d882612b91565b6120e28882611fc8565b97506120ed83612ae8565b9250506001016120c7565b611fed81612b02565b611fed81610494565b611fed61211682610494565b610494565b600061212682612ae0565b6121308185610482565b9350612140818560208601612b3b565b9290920192915050565b611fed81612b25565b600061215e82612ae0565b6121688185612aee565b9350612178818560208601612b3b565b61218181612b9d565b9093019392505050565b6000612198600a83612aee565b694d6178207374616b657360b01b815260200192915050565b60006121be601883612aee565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121f7601083612aee565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612223600e83612aee565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061224d601b83612aee565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612286601a83612aee565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122bf600d83612aee565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122e8602683612aee565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612330602083612aee565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612369601183612aee565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612396601c83612aee565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123cf601a83612aee565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b6000612408600e83612aee565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612432601583612aee565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612463602183612aee565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006124a6600e83612aee565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124d0600e83612aee565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124fa602e83612aee565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061254a601483612aee565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061257a600d83612aee565b6c24b73b30b634b210383937b7b360991b815260200192915050565b60006125a3602a83612aee565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125ef601283612aee565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b600061261d603083612aee565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b600061266f601f83612aee565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c08301906126ac8482612101565b5060208201516126bf6020850182612101565b5060408201516126d26040850182612101565b5060608201516126e5606085018261270b565b5060808201516126f860808501826120f8565b5060a08201516105aa60a085018261271d565b611fed81612b13565b611fed81612b30565b611fed81612b1f565b611fed61273282612b1f565b612b86565b6000612743828561210a565b602082019150612753828461210a565b5060200192915050565b6000610963828461211b565b6000612775828a61210a565b6020820191506127858289612726565b6001820191506127958288611fdc565b6014820191506127a58287611fdc565b6014820191506127b5828661210a565b6020820191506127c5828561210a565b6020820191506127d5828461210a565b50602001979650505050505050565b60208101610bfb8284611ff3565b606081016128008286611ff3565b61280d6020830185611ff3565b6117876040830184612101565b604081016128288285611ff3565b6109636020830184612101565b60208082528101610bf88184611ffc565b60208082528101610bf88184612055565b60208082528101610bf881846120a3565b60208101610bfb82846120f8565b604081016128288285612101565b60208101610bfb828461214a565b60208082528101610bf88184612153565b60208082528101610bfb8161218b565b60208082528101610bfb816121b1565b60208082528101610bfb816121ea565b60208082528101610bfb81612216565b60208082528101610bfb81612240565b60208082528101610bfb81612279565b60208082528101610bfb816122b2565b60208082528101610bfb816122db565b60208082528101610bfb81612323565b60208082528101610bfb8161235c565b60208082528101610bfb81612389565b60208082528101610bfb816123c2565b60208082528101610bfb816123fb565b60208082528101610bfb81612425565b60208082528101610bfb81612456565b60208082528101610bfb81612499565b60208082528101610bfb816124c3565b60208082528101610bfb816124ed565b60208082528101610bfb8161253d565b60208082528101610bfb8161256d565b60208082528101610bfb81612596565b60208082528101610bfb816125e2565b60208082528101610bfb81612610565b60208082528101610bfb81612662565b60208101610bfb8284612101565b60608101612a3f8286612101565b612a4c6020830185612101565b6117876040830184612714565b60c08101612a678289612101565b612a746020830188612101565b612a816040830187612101565b612a8e606083018661270b565b612a9b60808301856120f8565b612aa860a083018461271d565b979650505050505050565b60608101612ac1828661271d565b61280d6020830185612101565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612b07565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612af7565b6000610bfb82612b13565b60005b83811015612b56578181015183820152602001612b3e565b838111156105aa5750506000910152565b6000610bfb61211683610494565b6000610bfb826000610bfb82612bad565b6000610bfb82612ba7565b6000610bfb8254612b67565b601f01601f191690565b60f81b90565b60601b90565b612bbc81612af7565b81146115ea57600080fd5b612bbc81612b02565b612bbc81610494565b612bbc81612b1f56fea365627a7a723158200dfb3e06c3cb37079851ef4ebb60b603ca03e591e2736b87fa908d68d042d6576c6578706572696d656e74616cf564736f6c634300050b00407bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101a95760003560e01c806382d78111116100f9578063d38bfff411610097578063e9e518a011610071578063e9e518a01461038f578063e9fad8ee146103a2578063ea1d81cb146103aa578063ff5a20bf146103bd576101a9565b8063d38bfff414610348578063dd418ae21461035b578063df962bd61461036e576101a9565b8063b5d5b5fa116100d3578063b5d5b5fa146102f3578063bc20a7af14610318578063bc2ee5a61461032b578063c7af335214610340576101a9565b806382d78111146102ba5780639bfd8d61146102cd578063a5149d54146102e0576101a9565b80634f2b529d116101665780635e99cbe9116101405780635e99cbe91461026c57806372f702f31461027f5780637b0472f014610294578063825e0e80146102a7576101a9565b80634f2b529d1461023c5780635c975abb1461024f5780635d36b19014610264576101a9565b806304238994146101ae5780630c340a24146101d757806316078d04146101ec57806316c38b3c14610201578063334e7ed214610216578063389b21ce14610229575b600080fd5b6101c16101bc366004611c6d565b6103c5565b6040516101ce9190612835565b60405180910390f35b6101df610487565b6040516101ce91906127e4565b6101f4610497565b6040516101ce9190612a23565b61021461020f366004611e39565b61049d565b005b610214610224366004611dc9565b610519565b610214610237366004611f93565b6105b0565b61021461024a366004611ed0565b610650565b6102576108db565b6040516101ce9190612868565b6102146108e4565b61025761027a366004611d4c565b610927565b61028761096a565b6040516101ce9190612884565b6102146102a2366004611eb1565b610979565b6101f46102b5366004611e75565b610a29565b6101f46102c8366004611c6d565b610a43565b6101f46102db366004611c6d565b610b62565b6102576102ee366004611d99565b610bec565b610306610301366004611d12565b610c01565b6040516101ce96959493929190612a59565b6101f4610326366004611e75565b610c63565b610333610c81565b6040516101ce9190612846565b610257610cd9565b610214610356366004611c6d565b610cfc565b6101f4610369366004611e75565b610d73565b61038161037c366004611f75565b610d80565b6040516101ce929190612876565b61021461039d366004611c8b565b610d99565b610214610eca565b6101f46103b8366004611c6d565b6110ce565b6103336110ef565b6001600160a01b0381166000908152603860209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561047b5760008481526020908190206040805160c081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160f01b038116606084015260ff600160f01b8204811615156080850152600160f81b9091041660a083015290835290920191016103fd565b5050505090505b919050565b6000610491611145565b90505b90565b60365481565b6104a5610cd9565b6104ca5760405162461bcd60e51b81526004016104c1906128f3565b60405180910390fd5b6037805460ff1916821515179081905560405133917fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9161050e9160ff1690612868565b60405180910390a250565b610521610cd9565b61053d5760405162461bcd60e51b81526004016104c1906128f3565b6105aa8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061116a92505050565b50505050565b6105b8610cd9565b6105d45760405162461bcd60e51b81526004016104c1906128f3565b60ff83166105f45760405162461bcd60e51b81526004016104c1906128b3565b60ff831660009081526039602052604090819020838155600101829055517f1ac9c006454d2d601a481473a37c95bf489c5923bd7c2a701757d4016a0f022d9061064390859085908590612ab3565b60405180910390a1505050565b60ff86166106705760405162461bcd60e51b81526004016104c1906128b3565b6001600160f01b0384106106965760405162461bcd60e51b81526004016104c190612933565b600281900a87106106b95760405162461bcd60e51b81526004016104c190612903565b60ff86166000908152603960205260409020600181015482146106ee5760405162461bcd60e51b81526004016104c1906129d3565b6000888830338a8a8a60405160200161070d9796959493929190612769565b60408051601f19818403018152919052805160209091012090508860005b61ffff81168511156107d95781600116600114156107895785858261ffff1681811061075357fe5b905060200201358360405160200161076c929190612737565b6040516020818303038152906040528051906020012092506107cb565b8286868361ffff1681811061079a57fe5b905060200201356040516020016107b2929190612737565b6040516020818303038152906040528051906020012092505b60028204915060010161072b565b50825482146107fa5760405162461bcd60e51b81526004016104c1906129f3565b610804338a61128d565b156108215760405162461bcd60e51b81526004016104c190612993565b61082e338a8a8a8a611302565b50506036546033546040516370a0823160e01b81529192506001600160a01b0316906370a08231906108649030906004016127e4565b60206040518083038186803b15801561087c57600080fd5b505afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b49190810190611e93565b10156108d25760405162461bcd60e51b81526004016104c1906129c3565b50505050505050565b60375460ff1681565b6108ec61154f565b6001600160a01b0316336001600160a01b03161461091c5760405162461bcd60e51b81526004016104c190612a03565b61092533611574565b565b6033546000906001600160a01b031633146109545760405162461bcd60e51b81526004016104c190612913565b61095f8484846115ed565b5060015b9392505050565b6033546001600160a01b031681565b6109843383836115ed565b6036546033546040516370a0823160e01b81526001600160a01b03909116906370a08231906109b79030906004016127e4565b60206040518083038186803b1580156109cf57600080fd5b505afa1580156109e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a079190810190611e93565b1015610a255760405162461bcd60e51b81526004016104c1906129c3565b5050565b6000610a348261166f565b6001600160f01b031692915050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b576000828281548110610a7457fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff1615610aa15750610b53565b4281600101541015610acd57610ac6610ab9826116cd565b859063ffffffff6116f316565b9350610b51565b610b4e610ab9610b40610b158460020154610b09610af842886001015461171890919063ffffffff16565b60028801549063ffffffff61171816565b9063ffffffff61175a16565b60038501548554610b34916001600160f01b031663ffffffff61178f16565b9063ffffffff61178f16565b83549063ffffffff6116f316565b93505b505b600101610a5d565b5050919050565b6001600160a01b0381166000908152603860205260408120815b8154811015610b5b57818181548110610b9157fe5b9060005260206000209060040201600301601e9054906101000a900460ff16610be457610be1828281548110610bc357fe5b6000918252602090912060049091020154849063ffffffff6116f316565b92505b600101610b7c565b6000610bf8838361128d565b90505b92915050565b60386020528160005260406000208181548110610c1a57fe5b6000918252602090912060049091020180546001820154600283015460039093015491945092506001600160f01b0381169060ff600160f01b8204811691600160f81b90041686565b60348181548110610c7057fe5b600091825260209091200154905081565b60606034805480602002602001604051908101604052809291908181526020018280548015610ccf57602002820191906000526020600020905b815481526020019060010190808311610cbb575b5050505050905090565b6000610ce3611145565b6001600160a01b0316336001600160a01b031614905090565b610d04610cd9565b610d205760405162461bcd60e51b81526004016104c1906128f3565b610d29816117a4565b806001600160a01b0316610d3b611145565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60358181548110610c7057fe5b6039602052600090815260409020805460019091015482565b610da1610cd9565b610dbd5760405162461bcd60e51b81526004016104c1906128f3565b600054610100900460ff1680610dd65750610dd66117c8565b80610de4575060005460ff16155b610e005760405162461bcd60e51b81526004016104c1906129b3565b600054610100900460ff16158015610e2b576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0388161790556040805160208681028083018201909352868252610eb0928891889182918501908490808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061116a92505050565b8015610ec2576000805461ff00191690555b505050505050565b3360009081526038602052604090208054610ef75760405162461bcd60e51b81526004016104c1906129a3565b805460009081905b6000846001830381548110610f1057fe5b90600052602060002090600402019050428160010154108015610f3e57506003810154600160f01b900460ff165b15610f495750610f9a565b4281600101541015610f8f5760038101805460ff60f01b1916600160f01b179055610f76610ab9826116cd565b8154909450610f8c90849063ffffffff6116f316565b92505b506000190180610eff575b60008311610fba5760405162461bcd60e51b81526004016104c190612973565b603654610fcd908463ffffffff61171816565b60365560405133907f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6906110049086908690612876565b60405180910390a2603354611029906001600160a01b0316338563ffffffff6117ce16565b50506036546033546040516370a0823160e01b81529193506001600160a01b031691506370a08231906110609030906004016127e4565b60206040518083038186803b15801561107857600080fd5b505afa15801561108c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110b09190810190611e93565b10156109255760405162461bcd60e51b81526004016104c1906129c3565b6001600160a01b0381166000908152603860205260408120610bfb9061182c565b60606035805480602002602001604051908101604052809291908181526020018280548015610ccf5760200282019190600052602060002090815481526020019060010190808311610cbb575050505050905090565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a5490565b815181511461118b5760405162461bcd60e51b81526004016104c190612943565b60005b81518110156111dc576000196001600160f01b03168282815181106111af57fe5b6020026020010151106111d45760405162461bcd60e51b81526004016104c190612933565b60010161118e565b5080516111f0906035906020840190611b23565b508151611204906034906020850190611b23565b50336001600160a01b03167fa804368c7f1a6216d92d17d9753b923dfc3da14ae33d231e8d79e39202e249c3603560405161123f9190612857565b60405180910390a2336001600160a01b03167f180120279c2eb356244609197b5b64c0fbabd60f8d073b75aba771a296bb63d460346040516112819190612857565b60405180910390a25050565b6001600160a01b0382166000908152603860205260408120815b81548110156112f7578360ff168282815481106112c057fe5b6000918252602090912060049091020160030154600160f81b900460ff1614156112ef57600192505050610bfb565b6001016112a7565b506000949350505050565b60375460ff16156113255760405162461bcd60e51b81526004016104c190612963565b6001600160a01b03851660009081526038602052604081209061134e428663ffffffff6116f316565b825490915061010081106113745760405162461bcd60e51b81526004016104c1906128a3565b82546001016113838482611b6e565b505b80158015906113b357508183600183038154811061139f57fe5b906000526020600020906004020160010154115b1561147d578260018203815481106113c757fe5b90600052602060002090600402018382815481106113e157fe5b6000918252602090912082546004909202019081556001808301549082015560028083015490820155600391820180549290910180546001600160f01b0319166001600160f01b0390931692909217808355815460ff600160f01b918290048116151590910260ff60f01b19909216919091178084559154600160f81b90819004909116026001600160f81b0390911617905560001901611385565b600083828154811061148b57fe5b600091825260209091206004909102016003810180546001600160f01b0319166001600160f01b038916176001600160f81b0316600160f81b60ff8c1602179055600181018490556002810188905585815590506114fa6114eb826116cd565b6036549063ffffffff6116f316565b6036556040516001600160a01b038a16907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9061153c9088908b908b90612a31565b60405180910390a2505050505050505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db5490565b6001600160a01b03811661159a5760405162461bcd60e51b81526004016104c190612953565b806001600160a01b03166115ac611145565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a36115ea816118b0565b50565b6000821161160d5760405162461bcd60e51b81526004016104c1906128d3565b60006116188261166f565b90506000816001600160f01b0316116116435760405162461bcd60e51b81526004016104c1906128c3565b611651846000848487611302565b6033546105aa906001600160a01b031685308663ffffffff6118d416565b6000805b6034548110156116c4576034818154811061168a57fe5b90600052602060002001548314156116bc57603581815481106116a957fe5b9060005260206000200154915050610482565b600101611673565b50600092915050565b60038101548154600091610bfb91610b40916001600160f01b031663ffffffff61178f16565b600082820183811015610bf85760405162461bcd60e51b81526004016104c1906128e3565b6000610bf883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506118f8565b60008061177584670de0b6b3a764000063ffffffff61192416565b9050611787818463ffffffff61195e16565b949350505050565b6000610bf88383670de0b6b3a76400006119a0565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b303b1590565b60405161182790849063a9059cbb60e01b906117f0908690869060240161281a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526119ce565b505050565b6000805b82548110156118aa57600083828154811061184757fe5b9060005260206000209060040201905080600301601e9054906101000a900460ff166118a1576003810154815461189e9161189191906001600160f01b031663ffffffff61178f16565b849063ffffffff6116f316565b92505b50600101611830565b50919050565b7f7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a55565b6040516105aa9085906323b872dd60e01b906117f0908790879087906024016127f2565b6000818484111561191c5760405162461bcd60e51b81526004016104c19190612892565b505050900390565b60008261193357506000610bfb565b8282028284828161194057fe5b0414610bf85760405162461bcd60e51b81526004016104c190612983565b6000610bf883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611ab3565b6000806119b3858563ffffffff61192416565b90506119c5818463ffffffff61195e16565b95945050505050565b6119e0826001600160a01b0316611aea565b6119fc5760405162461bcd60e51b81526004016104c190612a13565b60006060836001600160a01b031683604051611a18919061275d565b6000604051808303816000865af19150503d8060008114611a55576040519150601f19603f3d011682016040523d82523d6000602084013e611a5a565b606091505b509150915081611a7c5760405162461bcd60e51b81526004016104c190612923565b8051156105aa5780806020019051611a979190810190611e57565b6105aa5760405162461bcd60e51b81526004016104c1906129e3565b60008183611ad45760405162461bcd60e51b81526004016104c19190612892565b506000838581611ae057fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611787575050151592915050565b828054828255906000526020600020908101928215611b5e579160200282015b82811115611b5e578251825591602001919060010190611b43565b50611b6a929150611b9a565b5090565b815481835581811115611827576004028160040283600052602060002091820191016118279190611bb4565b61049491905b80821115611b6a5760008155600101611ba0565b61049491905b80821115611b6a57600080825560018201819055600282018190556003820155600401611bba565b8035610bfb81612bb3565b60008083601f840112611bff57600080fd5b50813567ffffffffffffffff811115611c1757600080fd5b602083019150836020820283011115611c2f57600080fd5b9250929050565b8035610bfb81612bc7565b8051610bfb81612bc7565b8035610bfb81612bd0565b8051610bfb81612bd0565b8035610bfb81612bd9565b600060208284031215611c7f57600080fd5b60006117878484611be2565b600080600080600060608688031215611ca357600080fd5b6000611caf8888611be2565b955050602086013567ffffffffffffffff811115611ccc57600080fd5b611cd888828901611bed565b9450945050604086013567ffffffffffffffff811115611cf757600080fd5b611d0388828901611bed565b92509250509295509295909350565b60008060408385031215611d2557600080fd5b6000611d318585611be2565b9250506020611d4285828601611c4c565b9150509250929050565b600080600060608486031215611d6157600080fd5b6000611d6d8686611be2565b9350506020611d7e86828701611c4c565b9250506040611d8f86828701611c4c565b9150509250925092565b60008060408385031215611dac57600080fd5b6000611db88585611be2565b9250506020611d4285828601611c62565b60008060008060408587031215611ddf57600080fd5b843567ffffffffffffffff811115611df657600080fd5b611e0287828801611bed565b9450945050602085013567ffffffffffffffff811115611e2157600080fd5b611e2d87828801611bed565b95989497509550505050565b600060208284031215611e4b57600080fd5b60006117878484611c36565b600060208284031215611e6957600080fd5b60006117878484611c41565b600060208284031215611e8757600080fd5b60006117878484611c4c565b600060208284031215611ea557600080fd5b60006117878484611c57565b60008060408385031215611ec457600080fd5b6000611d318585611c4c565b600080600080600080600060c0888a031215611eeb57600080fd5b6000611ef78a8a611c4c565b9750506020611f088a828b01611c62565b9650506040611f198a828b01611c4c565b9550506060611f2a8a828b01611c4c565b9450506080611f3b8a828b01611c4c565b93505060a088013567ffffffffffffffff811115611f5857600080fd5b611f648a828b01611bed565b925092505092959891949750929550565b600060208284031215611f8757600080fd5b60006117878484611c62565b600080600060608486031215611fa857600080fd5b6000611d6d8686611c62565b6000611fc0838361269b565b505060c00190565b6000611fd48383612101565b505060200190565b611fed611fe882612af7565b612b75565b82525050565b611fed81612af7565b600061200782612ae0565b6120118185612aee565b935061201c83612ace565b8060005b8381101561204a5781516120348882611fb4565b975061203f83612ace565b925050600101612020565b509495945050505050565b600061206082612ae0565b61206a8185612aee565b935061207583612ace565b8060005b8381101561204a57815161208d8882611fc8565b975061209883612ace565b925050600101612079565b60006120ae82612ae4565b6120b88185612aee565b93506120c383612ad4565b8060005b8381101561204a576120d882612b91565b6120e28882611fc8565b97506120ed83612ae8565b9250506001016120c7565b611fed81612b02565b611fed81610494565b611fed61211682610494565b610494565b600061212682612ae0565b6121308185610482565b9350612140818560208601612b3b565b9290920192915050565b611fed81612b25565b600061215e82612ae0565b6121688185612aee565b9350612178818560208601612b3b565b61218181612b9d565b9093019392505050565b6000612198600a83612aee565b694d6178207374616b657360b01b815260200192915050565b60006121be601883612aee565b7f43616e6e6f74206265206e6f726d616c207374616b696e670000000000000000815260200192915050565b60006121f7601083612aee565b6f24b73b30b634b210323ab930ba34b7b760811b815260200192915050565b6000612223600e83612aee565b6d043616e6e6f74207374616b6520360941b815260200192915050565b600061224d601b83612aee565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612286601a83612aee565b7f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000815260200192915050565b60006122bf600d83612aee565b6c092dcecc2d8d2c840d2dcc8caf609b1b815260200192915050565b60006122e8602683612aee565b7f4f6e6c7920746f6b656e20636f6e74726163742063616e206d616b65207468698152651cc818d85b1b60d21b602082015260400192915050565b6000612330602083612aee565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612369601183612aee565b7013585e081c985d1948195e18d959591959607a1b815260200192915050565b6000612396601c83612aee565b7f4d69736d61746368206475726174696f6e7320616e6420726174657300000000815260200192915050565b60006123cf601a83612aee565b7f4e657720476f7665726e6f722069732061646472657373283029000000000000815260200192915050565b6000612408600e83612aee565b6d14dd185ada5b99c81c185d5cd95960921b815260200192915050565b6000612432601583612aee565b740416c6c207374616b657320696e206c6f636b2d757605c1b815260200192915050565b6000612463602183612aee565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006124a6600e83612aee565b6d105b1c9958591e481cdd185ad95960921b815260200192915050565b60006124d0600e83612aee565b6d139bdd1a1a5b99c81cdd185ad95960921b815260200192915050565b60006124fa602e83612aee565b7f436f6e747261637420696e7374616e63652068617320616c726561647920626581526d195b881a5b9a5d1a585b1a5e995960921b602082015260400192915050565b600061254a601483612aee565b73496e73756666696369656e74207265776172647360601b815260200192915050565b600061257a600d83612aee565b6c24b73b30b634b210383937b7b360991b815260200192915050565b60006125a3602a83612aee565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006125ef601283612aee565b7114dd185ad9481b9bdd08185c1c1c9bdd995960721b815260200192915050565b600061261d603083612aee565b7f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f81526f6d706c6574652074686520636c61696d60801b602082015260400192915050565b600061266f601f83612aee565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160c08301906126ac8482612101565b5060208201516126bf6020850182612101565b5060408201516126d26040850182612101565b5060608201516126e5606085018261270b565b5060808201516126f860808501826120f8565b5060a08201516105aa60a085018261271d565b611fed81612b13565b611fed81612b30565b611fed81612b1f565b611fed61273282612b1f565b612b86565b6000612743828561210a565b602082019150612753828461210a565b5060200192915050565b6000610963828461211b565b6000612775828a61210a565b6020820191506127858289612726565b6001820191506127958288611fdc565b6014820191506127a58287611fdc565b6014820191506127b5828661210a565b6020820191506127c5828561210a565b6020820191506127d5828461210a565b50602001979650505050505050565b60208101610bfb8284611ff3565b606081016128008286611ff3565b61280d6020830185611ff3565b6117876040830184612101565b604081016128288285611ff3565b6109636020830184612101565b60208082528101610bf88184611ffc565b60208082528101610bf88184612055565b60208082528101610bf881846120a3565b60208101610bfb82846120f8565b604081016128288285612101565b60208101610bfb828461214a565b60208082528101610bf88184612153565b60208082528101610bfb8161218b565b60208082528101610bfb816121b1565b60208082528101610bfb816121ea565b60208082528101610bfb81612216565b60208082528101610bfb81612240565b60208082528101610bfb81612279565b60208082528101610bfb816122b2565b60208082528101610bfb816122db565b60208082528101610bfb81612323565b60208082528101610bfb8161235c565b60208082528101610bfb81612389565b60208082528101610bfb816123c2565b60208082528101610bfb816123fb565b60208082528101610bfb81612425565b60208082528101610bfb81612456565b60208082528101610bfb81612499565b60208082528101610bfb816124c3565b60208082528101610bfb816124ed565b60208082528101610bfb8161253d565b60208082528101610bfb8161256d565b60208082528101610bfb81612596565b60208082528101610bfb816125e2565b60208082528101610bfb81612610565b60208082528101610bfb81612662565b60208101610bfb8284612101565b60608101612a3f8286612101565b612a4c6020830185612101565b6117876040830184612714565b60c08101612a678289612101565b612a746020830188612101565b612a816040830187612101565b612a8e606083018661270b565b612a9b60808301856120f8565b612aa860a083018461271d565b979650505050505050565b60608101612ac1828661271d565b61280d6020830185612101565b60200190565b60009081526020902090565b5190565b5490565b60010190565b90815260200190565b6000610bfb82612b07565b151590565b6001600160a01b031690565b6001600160f01b031690565b60ff1690565b6000610bfb82612af7565b6000610bfb82612b13565b60005b83811015612b56578181015183820152602001612b3e565b838111156105aa5750506000910152565b6000610bfb61211683610494565b6000610bfb826000610bfb82612bad565b6000610bfb82612ba7565b6000610bfb8254612b67565b601f01601f191690565b60f81b90565b60601b90565b612bbc81612af7565b81146115ea57600080fd5b612bbc81612b02565b612bbc81610494565b612bbc81612b1f56fea365627a7a723158200dfb3e06c3cb37079851ef4ebb60b603ca03e591e2736b87fa908d68d042d6576c6578706572696d656e74616cf564736f6c634300050b0040", "devdoc": { "methods": { "airDroppedStake(uint256,uint8,uint256,uint256,uint256,bytes32[])": { diff --git a/contracts/deployments/rinkeby/solcInputs/c7459e40fa663addef2a13f82ab72194.json b/contracts/deployments/rinkeby/solcInputs/c7459e40fa663addef2a13f82ab72194.json new file mode 100644 index 0000000000..8f9bd9516c --- /dev/null +++ b/contracts/deployments/rinkeby/solcInputs/c7459e40fa663addef2a13f82ab72194.json @@ -0,0 +1,287 @@ +{ + "language": "Solidity", + "sources": { + "contracts/compensation/CompensationClaims.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title Compensation Claims\n * @author Origin Protocol Inc\n * @dev Airdrop for ERC20 tokens.\n *\n * Provides a coin airdrop with a verification period in which everyone\n * can check that all claims are correct before any actual funds are moved\n * to the contract.\n *\n * - Users can claim funds during the claim period.\n *\n * - The adjuster can set the amount of each user's claim,\n * but only when unlocked, and not during the claim period.\n *\n * - The governor can unlock and lock the adjuster, outside the claim period.\n * - The governor can start the claim period, if it's not started.\n * - The governor can collect any remaining funds after the claim period is over.\n *\n * Intended use sequence:\n *\n * 1. Governor unlocks the adjuster\n * 2. Adjuster uploads claims\n * 3. Governor locks the adjuster\n * 4. Everyone verifies that the claim amounts and totals are correct\n * 5. Payout funds are moved to the contract\n * 6. The claim period starts\n * 7. Users claim funds\n * 8. The claim period ends\n * 9. Governor can collect any remaing funds\n *\n */\ncontract CompensationClaims is Governable {\n address public adjuster;\n address public token;\n uint256 public end;\n uint256 public totalClaims;\n mapping(address => uint256) claims;\n bool public isAdjusterLocked;\n\n using SafeMath for uint256;\n\n event Claim(address indexed recipient, uint256 amount);\n event ClaimSet(address indexed recipient, uint256 amount);\n event Start(uint256 end);\n event Lock();\n event Unlock();\n event Collect(address indexed coin, uint256 amount);\n\n constructor(address _token, address _adjuster) public onlyGovernor {\n token = _token;\n adjuster = _adjuster;\n isAdjusterLocked = true;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return claims[_account];\n }\n\n function decimals() external view returns (uint8) {\n return IERC20Decimals(token).decimals();\n }\n\n /* -- User -- */\n\n function claim(address _recipient) external onlyInClaimPeriod nonReentrant {\n uint256 amount = claims[_recipient];\n require(amount > 0, \"Amount must be greater than 0\");\n claims[_recipient] = 0;\n totalClaims = totalClaims.sub(amount);\n SafeERC20.safeTransfer(IERC20(token), _recipient, amount);\n emit Claim(_recipient, amount);\n }\n\n /* -- Adjustor -- */\n\n function setClaims(\n address[] calldata _addresses,\n uint256[] calldata _amounts\n ) external notInClaimPeriod onlyUnlockedAdjuster {\n require(\n _addresses.length == _amounts.length,\n \"Addresses and amounts must match\"\n );\n uint256 len = _addresses.length;\n for (uint256 i = 0; i < len; i++) {\n address recipient = _addresses[i];\n uint256 newAmount = _amounts[i];\n uint256 oldAmount = claims[recipient];\n claims[recipient] = newAmount;\n totalClaims = totalClaims.add(newAmount).sub(oldAmount);\n emit ClaimSet(recipient, newAmount);\n }\n }\n\n /* -- Governor -- */\n\n function lockAdjuster() external onlyGovernor notInClaimPeriod {\n _lockAdjuster();\n }\n\n function _lockAdjuster() internal {\n isAdjusterLocked = true;\n emit Lock();\n }\n\n function unlockAdjuster() external onlyGovernor notInClaimPeriod {\n isAdjusterLocked = false;\n emit Unlock();\n }\n\n function start(uint256 _seconds)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n require(totalClaims > 0, \"No claims\");\n uint256 funding = IERC20(token).balanceOf(address(this));\n require(funding >= totalClaims, \"Insufficient funds for all claims\");\n _lockAdjuster();\n end = block.timestamp.add(_seconds);\n require(end.sub(block.timestamp) < 31622400, \"Duration too long\"); // 31622400 = 366*24*60*60\n emit Start(end);\n }\n\n function collect(address _coin)\n external\n onlyGovernor\n notInClaimPeriod\n nonReentrant\n {\n uint256 amount = IERC20(_coin).balanceOf(address(this));\n SafeERC20.safeTransfer(IERC20(_coin), address(governor()), amount);\n emit Collect(_coin, amount);\n }\n\n /* -- modifiers -- */\n\n modifier onlyInClaimPeriod() {\n require(block.timestamp <= end, \"Should be in claim period\");\n _;\n }\n\n modifier notInClaimPeriod() {\n require(block.timestamp > end, \"Should not be in claim period\");\n _;\n }\n\n modifier onlyUnlockedAdjuster() {\n require(isAdjusterLocked == false, \"Adjuster must be unlocked\");\n require(msg.sender == adjuster, \"Must be adjuster\");\n _;\n }\n}\n\ninterface IERC20Decimals {\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/upgrades/contracts/Initializable.sol": { + "content": "pragma solidity >=0.4.24 <0.7.0;\n\n\n/**\n * @title Initializable\n *\n * @dev Helper contract to support initializer functions. To use it, replace\n * the constructor with a function that has the `initializer` modifier.\n * WARNING: Unlike constructors, initializer functions must be manually\n * invoked. This applies both to deploying an Initializable contract, as well\n * as extending an Initializable contract via inheritance.\n * WARNING: When used with inheritance, manual care must be taken to not invoke\n * a parent initializer twice, or ensure that all initializers are idempotent,\n * because this is not dealt with automatically as with constructors.\n */\ncontract Initializable {\n\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to use in the initializer function of a contract.\n */\n modifier initializer() {\n require(initializing || isConstructor() || !initialized, \"Contract instance has already been initialized\");\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n /// @dev Returns true if and only if the function is running in the constructor\n function isConstructor() private view returns (bool) {\n // extcodesize checks the size of the code stored in an address, and\n // address returns the current address. Since the code is still not\n // deployed when running a constructor, any checks on its code size will\n // yield zero, making it an effective way to detect if a contract is\n // under construction or not.\n address self = address(this);\n uint256 cs;\n assembly { cs := extcodesize(self) }\n return cs == 0;\n }\n\n // Reserved storage space to allow for layout changes in the future.\n uint256[50] private ______gap;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/SafeERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n function safeApprove(IERC20 token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require((value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) { // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/math/SafeMath.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Governable Contract\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n * from owner to governor and renounce methods removed. Does not use\n * Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\ncontract Governable {\n // Storage position of the owner and pendingOwner of the contract\n // keccak256(\"OUSD.governor\");\n bytes32\n private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32\n private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32\n private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n // See OpenZeppelin ReentrancyGuard implementation\n uint256 constant _NOT_ENTERED = 1;\n uint256 constant _ENTERED = 2;\n\n event PendingGovernorshipTransfer(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n event GovernorshipTransferred(\n address indexed previousGovernor,\n address indexed newGovernor\n );\n\n /**\n * @dev Initializes the contract setting the deployer as the initial Governor.\n */\n constructor() internal {\n _setGovernor(msg.sender);\n emit GovernorshipTransferred(address(0), _governor());\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function governor() public view returns (address) {\n return _governor();\n }\n\n /**\n * @dev Returns the address of the current Governor.\n */\n function _governor() internal view returns (address governorOut) {\n bytes32 position = governorPosition;\n assembly {\n governorOut := sload(position)\n }\n }\n\n /**\n * @dev Returns the address of the pending Governor.\n */\n function _pendingGovernor()\n internal\n view\n returns (address pendingGovernor)\n {\n bytes32 position = pendingGovernorPosition;\n assembly {\n pendingGovernor := sload(position)\n }\n }\n\n /**\n * @dev Throws if called by any account other than the Governor.\n */\n modifier onlyGovernor() {\n require(isGovernor(), \"Caller is not the Governor\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current Governor.\n */\n function isGovernor() public view returns (bool) {\n return msg.sender == _governor();\n }\n\n function _setGovernor(address newGovernor) internal {\n bytes32 position = governorPosition;\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n bytes32 position = reentryStatusPosition;\n uint256 _reentry_status;\n assembly {\n _reentry_status := sload(position)\n }\n\n // On the first call to nonReentrant, _notEntered will be true\n require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n assembly {\n sstore(position, _ENTERED)\n }\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n assembly {\n sstore(position, _NOT_ENTERED)\n }\n }\n\n function _setPendingGovernor(address newGovernor) internal {\n bytes32 position = pendingGovernorPosition;\n assembly {\n sstore(position, newGovernor)\n }\n }\n\n /**\n * @dev Transfers Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the current Governor. Must be claimed for this to complete\n * @param _newGovernor Address of the new Governor\n */\n function transferGovernance(address _newGovernor) external onlyGovernor {\n _setPendingGovernor(_newGovernor);\n emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n }\n\n /**\n * @dev Claim Governance of the contract to a new account (`newGovernor`).\n * Can only be called by the new Governor.\n */\n function claimGovernance() external {\n require(\n msg.sender == _pendingGovernor(),\n \"Only the pending Governor can complete the claim\"\n );\n _changeGovernor(msg.sender);\n }\n\n /**\n * @dev Change Governance of the contract to a new account (`newGovernor`).\n * @param _newGovernor Address of the new Governor\n */\n function _changeGovernor(address _newGovernor) internal {\n require(_newGovernor != address(0), \"New Governor is address(0)\");\n emit GovernorshipTransferred(_governor(), _newGovernor);\n _setGovernor(_newGovernor);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "pragma solidity ^0.5.5;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following \n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly { codehash := extcodehash(account) }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract InitializableAbstractStrategy is Initializable, Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n event PTokenAdded(address indexed _asset, address _pToken);\n event PTokenRemoved(address indexed _asset, address _pToken);\n event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n event RewardTokenCollected(address recipient, uint256 amount);\n\n // Core address for the given platform\n address public platformAddress;\n\n address public vaultAddress;\n\n // asset => pToken (Platform Specific Token Address)\n mapping(address => address) public assetToPToken;\n\n // Full list of all assets supported here\n address[] internal assetsMapped;\n\n // Reward token address\n address public rewardTokenAddress;\n uint256 public rewardLiquidationThreshold;\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _platformAddress jGeneric platform address\n * @param _vaultAddress Address of the Vault\n * @param _rewardTokenAddress Address of reward token for platform\n * @param _assets Addresses of initial supported assets\n * @param _pTokens Platform Token corresponding addresses\n */\n function initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address[] calldata _assets,\n address[] calldata _pTokens\n ) external onlyGovernor initializer {\n InitializableAbstractStrategy._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n }\n\n /**\n * @dev Collect accumulated reward token (COMP) and send to Vault.\n */\n function collectRewardToken() external onlyVault nonReentrant {\n IERC20 rewardToken = IERC20(rewardTokenAddress);\n uint256 balance = rewardToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, balance);\n rewardToken.safeTransfer(vaultAddress, balance);\n }\n\n function _initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address[] memory _assets,\n address[] memory _pTokens\n ) internal {\n platformAddress = _platformAddress;\n vaultAddress = _vaultAddress;\n rewardTokenAddress = _rewardTokenAddress;\n uint256 assetCount = _assets.length;\n require(assetCount == _pTokens.length, \"Invalid input arrays\");\n for (uint256 i = 0; i < assetCount; i++) {\n _setPTokenAddress(_assets[i], _pTokens[i]);\n }\n }\n\n /**\n * @dev Single asset variant of the internal initialize.\n */\n function _initialize(\n address _platformAddress,\n address _vaultAddress,\n address _rewardTokenAddress,\n address _asset,\n address _pToken\n ) internal {\n platformAddress = _platformAddress;\n vaultAddress = _vaultAddress;\n rewardTokenAddress = _rewardTokenAddress;\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @dev Verifies that the caller is the Vault.\n */\n modifier onlyVault() {\n require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == vaultAddress || msg.sender == governor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n /**\n * @dev Set the reward token address.\n * @param _rewardTokenAddress Address of the reward token\n */\n function setRewardTokenAddress(address _rewardTokenAddress)\n external\n onlyGovernor\n {\n rewardTokenAddress = _rewardTokenAddress;\n }\n\n /**\n * @dev Set the reward token liquidation threshold.\n * @param _threshold Threshold amount in decimals of reward token that will\n * cause the Vault to claim and withdrawAll on allocate() calls.\n */\n function setRewardLiquidationThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n rewardLiquidationThreshold = _threshold;\n }\n\n /**\n * @dev Provide support for asset by passing its pToken address.\n * This method can only be called by the system Governor\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function setPTokenAddress(address _asset, address _pToken)\n external\n onlyGovernor\n {\n _setPTokenAddress(_asset, _pToken);\n }\n\n /**\n * @dev Remove a supported asset by passing its index.\n * This method can only be called by the system Governor\n * @param _assetIndex Index of the asset to be removed\n */\n function removePToken(uint256 _assetIndex) external onlyGovernor {\n require(_assetIndex < assetsMapped.length, \"Invalid index\");\n address asset = assetsMapped[_assetIndex];\n address pToken = assetToPToken[asset];\n\n if (_assetIndex < assetsMapped.length - 1) {\n assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n }\n assetsMapped.pop();\n assetToPToken[asset] = address(0);\n\n emit PTokenRemoved(asset, pToken);\n }\n\n /**\n * @dev Provide support for asset by passing its pToken address.\n * Add to internal mappings and execute the platform specific,\n * abstract method `_abstractSetPToken`\n * @param _asset Address for the asset\n * @param _pToken Address for the corresponding platform token\n */\n function _setPTokenAddress(address _asset, address _pToken) internal {\n require(assetToPToken[_asset] == address(0), \"pToken already set\");\n require(\n _asset != address(0) && _pToken != address(0),\n \"Invalid addresses\"\n );\n\n assetToPToken[_asset] = _pToken;\n assetsMapped.push(_asset);\n\n emit PTokenAdded(_asset, _pToken);\n\n _abstractSetPToken(_asset, _pToken);\n }\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * strategy contracts, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n public\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /***************************************\n Abstract\n ****************************************/\n\n function _abstractSetPToken(address _asset, address _pToken) internal;\n\n function safeApproveAllTokens() external;\n\n /**\n * @dev Deposit a amount of asset into the platform\n * @param _asset Address for the asset\n * @param _amount Units of asset to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Withdraw an amount of asset from the platform.\n * @param _recipient Address to which the asset should be sent\n * @param _asset Address of the asset\n * @param _amount Units of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Withdraw all assets from strategy sending assets to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Get the total asset value held in the platform.\n * This includes any interest that was generated since depositing.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Check if an asset is supported.\n * @param _asset Address of the asset\n * @return bool Whether asset is supported\n */\n function supportsAsset(address _asset) external view returns (bool);\n}\n" + }, + "contracts/strategies/ThreePoolStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICurveGauge } from \"./ICurveGauge.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\ncontract ThreePoolStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n\n event RewardTokenCollected(address recipient, uint256 amount);\n\n address crvGaugeAddress;\n address crvMinterAddress;\n int128 poolCoinIndex = -1;\n uint256 constant maxSlippage = 1e16; // 1%, same as the Curve UI\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as Curve strategies don't fit\n * well within that abstraction.\n * @param _platformAddress Address of the Curve 3pool\n * @param _vaultAddress Address of the vault\n * @param _rewardTokenAddress Address of CRV\n * @param _asset Address of the supported asset\n * @param _pToken Correspond platform token addres (i.e. 3Crv)\n * @param _crvGaugeAddress Address of the Curve DAO gauge for this pool\n * @param _crvMinterAddress Address of the CRV minter for rewards\n */\n function initialize(\n address _platformAddress, // 3Pool address\n address _vaultAddress,\n address _rewardTokenAddress, // CRV\n address _asset,\n address _pToken,\n address _crvGaugeAddress,\n address _crvMinterAddress\n ) external onlyGovernor initializer {\n ICurvePool threePool = ICurvePool(_platformAddress);\n for (int128 i = 0; i < 3; i++) {\n if (threePool.coins(uint256(i)) == _asset) poolCoinIndex = i;\n }\n require(poolCoinIndex != -1, \"Invalid 3pool asset\");\n crvGaugeAddress = _crvGaugeAddress;\n crvMinterAddress = _crvMinterAddress;\n InitializableAbstractStrategy._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _asset,\n _pToken\n );\n }\n\n /**\n * @dev Collect accumulated CRV and send to Vault.\n */\n function collectRewardToken() external onlyVault nonReentrant {\n IERC20 crvToken = IERC20(rewardTokenAddress);\n ICRVMinter minter = ICRVMinter(crvMinterAddress);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, balance);\n minter.mint(crvGaugeAddress);\n crvToken.safeTransfer(vaultAddress, balance);\n }\n\n /**\n * @dev Deposit asset into the Curve 3Pool\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n emit Deposit(_asset, address(platformAddress), _amount);\n // 3Pool requires passing deposit amounts for all 3 assets, set to 0 for\n // all\n uint256[3] memory _amounts;\n // Set the amount on the asset we want to deposit\n _amounts[uint256(poolCoinIndex)] = _amount;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 depositValue = _amount\n .scaleBy(int8(18 - assetDecimals))\n .divPrecisely(curvePool.get_virtual_price());\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n // Deposit into Gauge\n IERC20 pToken = IERC20(assetToPToken[_asset]);\n ICurveGauge(crvGaugeAddress).deposit(\n pToken.balanceOf(address(this)),\n address(this)\n );\n }\n\n /**\n * @dev Withdraw asset from Curve 3Pool\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_recipient != address(0), \"Invalid recipient\");\n require(_amount > 0, \"Invalid amount\");\n\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\n\n // Calculate how much of the pool token we need to withdraw\n (uint256 contractPTokens, , uint256 totalPTokens) = _getTotalPTokens();\n // Calculate the max amount of the asset we'd get if we withdrew all the\n // platform tokens\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 maxAmount = curvePool.calc_withdraw_one_coin(\n totalPTokens,\n poolCoinIndex\n );\n // Calculate how many platform tokens we need to withdraw the asset amount\n uint256 withdrawPTokens = totalPTokens.mul(_amount).div(maxAmount);\n if (contractPTokens < withdrawPTokens) {\n // Not enough of pool token exists on this contract, must be staked\n // in Gauge, unstake\n ICurveGauge(crvGaugeAddress).withdraw(withdrawPTokens);\n }\n uint256 minWithdrawAmount = withdrawPTokens.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n curvePool.remove_liquidity_one_coin(\n withdrawPTokens,\n poolCoinIndex,\n minWithdrawAmount\n );\n IERC20(_asset).safeTransfer(_recipient, _amount);\n // Transfer any leftover dust back to the vault buffer.\n uint256 dust = IERC20(_asset).balanceOf(address(this));\n if (dust > 0) {\n IERC20(_asset).safeTransfer(vaultAddress, dust);\n }\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n // Withdraw all from Gauge\n (, uint256 gaugePTokens, ) = _getTotalPTokens();\n ICurveGauge(crvGaugeAddress).withdraw(gaugePTokens);\n // Remove entire balance, 3pool strategies only support a single asset\n // so safe to use assetsMapped[0]\n IERC20 asset = IERC20(assetsMapped[0]);\n uint256 pTokenBalance = IERC20(assetToPToken[address(asset)]).balanceOf(\n address(this)\n );\n uint256 minWithdrawAmount = pTokenBalance.mulTruncate(\n uint256(1e18).sub(maxSlippage)\n );\n ICurvePool(platformAddress).remove_liquidity_one_coin(\n pTokenBalance,\n poolCoinIndex,\n minWithdrawAmount\n );\n // Transfer the asset out to Vault\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * This includes any interest that was generated since depositing\n * We calculate this by calculating a what we would get if we withdrawAlld\n * the allocated percentage of this asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // LP tokens in this contract. This should generally be nothing as we\n // should always stake the full balance in the Gauge, but include for\n // safety\n (, , uint256 totalPTokens) = _getTotalPTokens();\n balance = 0;\n if (totalPTokens > 0) {\n balance += ICurvePool(platformAddress).calc_withdraw_one_coin(\n totalPTokens,\n poolCoinIndex\n );\n }\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding pool tokens,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external {\n // This strategy is a special case since it only supports one asset\n address assetAddress = assetsMapped[0];\n _abstractSetPToken(assetAddress, assetToPToken[assetAddress]);\n }\n\n /**\n * @dev Calculate the total platform token balance (i.e. 3CRV) that exist in\n * this contract or is staked in the Gauge (or in other words, the total\n * amount platform tokens we own).\n * @return totalPTokens Total amount of platform tokens in native decimals\n */\n function _getTotalPTokens()\n internal\n view\n returns (\n uint256 contractPTokens,\n uint256 gaugePTokens,\n uint256 totalPTokens\n )\n {\n contractPTokens = IERC20(assetToPToken[assetsMapped[0]]).balanceOf(\n address(this)\n );\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n gaugePTokens = gauge.balanceOf(address(this));\n totalPTokens = contractPTokens.add(gaugePTokens);\n }\n\n /**\n * @dev Call the necessary approvals for the Curve pool and gauge\n * @param _asset Address of the asset\n * @param _pToken Address of the corresponding platform token (i.e. 3CRV)\n */\n function _abstractSetPToken(address _asset, address _pToken) internal {\n IERC20 asset = IERC20(_asset);\n IERC20 pToken = IERC20(_pToken);\n // 3Pool for asset (required for adding liquidity)\n asset.safeApprove(platformAddress, 0);\n asset.safeApprove(platformAddress, uint256(-1));\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, uint256(-1));\n // Gauge for LP token\n pToken.safeApprove(crvGaugeAddress, 0);\n pToken.safeApprove(crvGaugeAddress, uint256(-1));\n }\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICurvePool {\n function get_virtual_price() external returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function calc_token_amount(uint256[3] calldata _amounts, bool _deposit)\n external\n returns (uint256);\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external;\n\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n external\n view\n returns (uint256);\n\n function coins(uint256 _index) external view returns (address);\n}\n" + }, + "contracts/strategies/ICurveGauge.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICurveGauge {\n function balanceOf(address account) external view returns (uint256);\n\n function deposit(uint256 value, address account) external;\n\n function withdraw(uint256 value) external;\n}\n" + }, + "contracts/strategies/ICRVMinter.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface ICRVMinter {\n function mint(address gaugeAddress) external;\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\n\n// Based on StableMath from Stability Labs Pty. Ltd.\n// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol\n\nlibrary StableMath {\n using SafeMath for uint256;\n\n /**\n * @dev Scaling unit for use in specific calculations,\n * where 1 * 10**18, or 1e18 represents a unit '1'\n */\n uint256 private constant FULL_SCALE = 1e18;\n\n /***************************************\n Helpers\n ****************************************/\n\n /**\n * @dev Adjust the scale of an integer\n * @param adjustment Amount to adjust by e.g. scaleBy(1e18, -1) == 1e17\n */\n function scaleBy(uint256 x, int8 adjustment)\n internal\n pure\n returns (uint256)\n {\n if (adjustment > 0) {\n x = x.mul(10**uint256(adjustment));\n } else if (adjustment < 0) {\n x = x.div(10**uint256(adjustment * -1));\n }\n return x;\n }\n\n /***************************************\n Precise Arithmetic\n ****************************************/\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulTruncateScale(x, y, FULL_SCALE);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the given scale. For example,\n * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @param scale Scale unit\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit\n */\n function mulTruncateScale(\n uint256 x,\n uint256 y,\n uint256 scale\n ) internal pure returns (uint256) {\n // e.g. assume scale = fullScale\n // z = 10e18 * 9e17 = 9e36\n uint256 z = x.mul(y);\n // return 9e38 / 1e18 = 9e18\n return z.div(scale);\n }\n\n /**\n * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result\n * @param x Left hand input to multiplication\n * @param y Right hand input to multiplication\n * @return Result after multiplying the two inputs and then dividing by the shared\n * scale unit, rounded up to the closest base unit.\n */\n function mulTruncateCeil(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e17 * 17268172638 = 138145381104e17\n uint256 scaled = x.mul(y);\n // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17\n uint256 ceil = scaled.add(FULL_SCALE.sub(1));\n // e.g. 13814538111.399...e18 / 1e18 = 13814538111\n return ceil.div(FULL_SCALE);\n }\n\n /**\n * @dev Precisely divides two units, by first scaling the left hand operand. Useful\n * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)\n * @param x Left hand input to division\n * @param y Right hand input to division\n * @return Result after multiplying the left operand by the scale, and\n * executing the division on the right hand input.\n */\n function divPrecisely(uint256 x, uint256 y)\n internal\n pure\n returns (uint256)\n {\n // e.g. 8e18 * 1e18 = 8e36\n uint256 z = x.mul(FULL_SCALE);\n // e.g. 8e36 / 10e18 = 8e17\n return z.div(y);\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n /**\n * @notice Fetch the `symbol()` from an ERC20 token\n * @dev Grabs the `symbol()` from a contract\n * @param _token Address of the ERC20 token\n * @return string Symbol of the ERC20 token\n */\n function getSymbol(address _token) internal view returns (string memory) {\n string memory symbol = IBasicToken(_token).symbol();\n return symbol;\n }\n\n /**\n * @notice Fetch the `decimals()` from an ERC20 token\n * @dev Grabs the `decimals()` from a contract and fails if\n * the decimal value does not live within a certain range\n * @param _token Address of the ERC20 token\n * @return uint256 Decimals of the ERC20 token\n */\n function getDecimals(address _token) internal view returns (uint256) {\n uint256 decimals = IBasicToken(_token).decimals();\n require(\n decimals >= 4 && decimals <= 18,\n \"Token must have sufficient decimal places\"\n );\n\n return decimals;\n }\n}\n" + }, + "contracts/interfaces/IBasicToken.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/vault/VaultStorage.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultStorage Contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract VaultStorage is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeMath for int256;\n using SafeERC20 for IERC20;\n\n event AssetSupported(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event CapitalPaused();\n event CapitalUnpaused();\n event RebasePaused();\n event RebaseUnpaused();\n event VaultBufferUpdated(uint256 _vaultBuffer);\n event RedeemFeeUpdated(uint256 _redeemFeeBps);\n event PriceProviderUpdated(address _priceProvider);\n event AllocateThresholdUpdated(uint256 _threshold);\n event RebaseThresholdUpdated(uint256 _threshold);\n event UniswapUpdated(address _address);\n event StrategistUpdated(address _address);\n event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n\n // Assets supported by the Vault, i.e. Stablecoins\n struct Asset {\n bool isSupported;\n }\n mapping(address => Asset) assets;\n address[] allAssets;\n\n // Strategies approved for use by the Vault\n struct Strategy {\n bool isSupported;\n uint256 _deprecated; // Deprecated storage slot\n }\n mapping(address => Strategy) strategies;\n address[] allStrategies;\n\n // Address of the Oracle price provider contract\n address public priceProvider;\n // Pausing bools\n bool public rebasePaused = false;\n bool public capitalPaused = true;\n // Redemption fee in basis points\n uint256 public redeemFeeBps;\n // Buffer of assets to keep in Vault to handle (most) withdrawals\n uint256 public vaultBuffer;\n // Mints over this amount automatically allocate funds. 18 decimals.\n uint256 public autoAllocateThreshold;\n // Mints over this amount automatically rebase. 18 decimals.\n uint256 public rebaseThreshold;\n\n OUSD oUSD;\n\n //keccak256(\"OUSD.vault.governor.admin.impl\");\n bytes32 constant adminImplPosition = 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9;\n\n // Address of the contract responsible for post rebase syncs with AMMs\n address private _deprecated_rebaseHooksAddr = address(0);\n\n // Address of Uniswap\n address public uniswapAddr = address(0);\n\n // Address of the Strategist\n address public strategistAddr = address(0);\n\n // Mapping of asset address to the Strategy that they should automatically\n // be allocated to\n mapping(address => address) public assetDefaultStrategies;\n\n uint256 public maxSupplyDiff;\n\n /**\n * @dev set the implementation for the admin, this needs to be in a base class else we cannot set it\n * @param newImpl address of the implementation\n */\n function setAdminImpl(address newImpl) external onlyGovernor {\n require(\n Address.isContract(newImpl),\n \"new implementation is not a contract\"\n );\n bytes32 position = adminImplPosition;\n assembly {\n sstore(position, newImpl)\n }\n }\n}\n" + }, + "contracts/interfaces/IStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n /**\n * @dev Deposit the given asset to Lending platform.\n * @param _asset asset address\n * @param _amount Amount to deposit\n */\n function deposit(address _asset, uint256 _amount) external;\n\n /**\n * @dev Withdraw given asset from Lending platform\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external;\n\n /**\n * @dev Liquidate all assets in strategy and return them to Vault.\n */\n function withdrawAll() external;\n\n /**\n * @dev Returns the current balance of the given asset.\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance);\n\n /**\n * @dev Returns bool indicating whether strategy supports asset.\n */\n function supportsAsset(address _asset) external view returns (bool);\n\n /**\n * @dev Collect reward tokens from the Strategy.\n */\n function collectRewardToken() external;\n\n /**\n * @dev The address of the reward token for the Strategy.\n */\n function rewardTokenAddress() external pure returns (address);\n\n /**\n * @dev The threshold (denominated in the reward token) over which the\n * vault will auto harvest on allocate calls.\n */\n function rewardLiquidationThreshold() external pure returns (uint256);\n}\n" + }, + "contracts/token/OUSD.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport {\n InitializableERC20Detailed\n} from \"../utils/InitializableERC20Detailed.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * NOTE that this is an ERC20 token but the invariant that the sum of\n * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the\n * rebasing design. Any integrations with OUSD should be aware.\n */\n\ncontract OUSD is Initializable, InitializableERC20Detailed, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n\n event TotalSupplyUpdated(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n\n enum RebaseOptions { NotSet, OptOut, OptIn }\n\n uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1\n uint256 public _totalSupply;\n mapping(address => mapping(address => uint256)) private _allowances;\n address public vaultAddress = address(0);\n mapping(address => uint256) private _creditBalances;\n uint256 public rebasingCredits;\n uint256 public rebasingCreditsPerToken;\n // Frozen address/credits are non rebasing (value is held in contracts which\n // do not receive yield unless they explicitly opt in)\n uint256 public nonRebasingSupply;\n mapping(address => uint256) public nonRebasingCreditsPerToken;\n mapping(address => RebaseOptions) public rebaseState;\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress\n ) external onlyGovernor initializer {\n InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);\n rebasingCreditsPerToken = 1e18;\n vaultAddress = _vaultAddress;\n }\n\n /**\n * @dev Verifies that the caller is the Savings Manager contract\n */\n modifier onlyVault() {\n require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @return The total supply of OUSD.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Gets the balance of the specified address.\n * @param _account Address to query the balance of.\n * @return A uint256 representing the _amount of base units owned by the\n * specified address.\n */\n function balanceOf(address _account) public view returns (uint256) {\n if (_creditBalances[_account] == 0) return 0;\n return\n _creditBalances[_account].divPrecisely(_creditsPerToken(_account));\n }\n\n /**\n * @dev Gets the credits balance of the specified address.\n * @param _account The address to query the balance of.\n * @return (uint256, uint256) Credit balance and credits per token of the\n * address\n */\n function creditsBalanceOf(address _account)\n public\n view\n returns (uint256, uint256)\n {\n return (_creditBalances[_account], _creditsPerToken(_account));\n }\n\n /**\n * @dev Transfer tokens to a specified address.\n * @param _to the address to transfer to.\n * @param _value the _amount to be transferred.\n * @return true on success.\n */\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(\n _value <= balanceOf(msg.sender),\n \"Transfer greater than balance\"\n );\n\n _executeTransfer(msg.sender, _to, _value);\n\n emit Transfer(msg.sender, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Transfer tokens from one address to another.\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value The _amount of tokens to be transferred.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n require(_to != address(0), \"Transfer to zero address\");\n require(_value <= balanceOf(_from), \"Transfer greater than balance\");\n\n _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub(\n _value\n );\n\n _executeTransfer(_from, _to, _value);\n\n emit Transfer(_from, _to, _value);\n\n return true;\n }\n\n /**\n * @dev Update the count of non rebasing credits in response to a transfer\n * @param _from The address you want to send tokens from.\n * @param _to The address you want to transfer to.\n * @param _value Amount of OUSD to transfer\n */\n function _executeTransfer(\n address _from,\n address _to,\n uint256 _value\n ) internal {\n bool isNonRebasingTo = _isNonRebasingAccount(_to);\n bool isNonRebasingFrom = _isNonRebasingAccount(_from);\n\n // Credits deducted and credited might be different due to the\n // differing creditsPerToken used by each account\n uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to));\n uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from));\n\n _creditBalances[_from] = _creditBalances[_from].sub(\n creditsDeducted,\n \"Transfer amount exceeds balance\"\n );\n _creditBalances[_to] = _creditBalances[_to].add(creditsCredited);\n\n if (isNonRebasingTo && !isNonRebasingFrom) {\n // Transfer to non-rebasing account from rebasing account, credits\n // are removed from the non rebasing tally\n nonRebasingSupply = nonRebasingSupply.add(_value);\n // Update rebasingCredits by subtracting the deducted amount\n rebasingCredits = rebasingCredits.sub(creditsDeducted);\n } else if (!isNonRebasingTo && isNonRebasingFrom) {\n // Transfer to rebasing account from non-rebasing account\n // Decreasing non-rebasing credits by the amount that was sent\n nonRebasingSupply = nonRebasingSupply.sub(_value);\n // Update rebasingCredits by adding the credited amount\n rebasingCredits = rebasingCredits.add(creditsCredited);\n }\n }\n\n /**\n * @dev Function to check the _amount of tokens that an owner has allowed to a _spender.\n * @param _owner The address which owns the funds.\n * @param _spender The address which will spend the funds.\n * @return The number of tokens still available for the _spender.\n */\n function allowance(address _owner, address _spender)\n public\n view\n returns (uint256)\n {\n return _allowances[_owner][_spender];\n }\n\n /**\n * @dev Approve the passed address to spend the specified _amount of tokens on behalf of\n * msg.sender. This method is included for ERC20 compatibility.\n * increaseAllowance and decreaseAllowance should be used instead.\n * Changing an allowance with this method brings the risk that someone may transfer both\n * the old and the new allowance - if they are both greater than zero - if a transfer\n * transaction is mined before the later approve() call is mined.\n *\n * @param _spender The address which will spend the funds.\n * @param _value The _amount of tokens to be spent.\n */\n function approve(address _spender, uint256 _value) public returns (bool) {\n _allowances[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @dev Increase the _amount of tokens that an owner has allowed to a _spender.\n * This method should be used instead of approve() to avoid the double approval vulnerability\n * described above.\n * @param _spender The address which will spend the funds.\n * @param _addedValue The _amount of tokens to increase the allowance by.\n */\n function increaseAllowance(address _spender, uint256 _addedValue)\n public\n returns (bool)\n {\n _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender]\n .add(_addedValue);\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Decrease the _amount of tokens that an owner has allowed to a _spender.\n * @param _spender The address which will spend the funds.\n * @param _subtractedValue The _amount of tokens to decrease the allowance by.\n */\n function decreaseAllowance(address _spender, uint256 _subtractedValue)\n public\n returns (bool)\n {\n uint256 oldValue = _allowances[msg.sender][_spender];\n if (_subtractedValue >= oldValue) {\n _allowances[msg.sender][_spender] = 0;\n } else {\n _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue);\n }\n emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]);\n return true;\n }\n\n /**\n * @dev Mints new tokens, increasing totalSupply.\n */\n function mint(address _account, uint256 _amount) external onlyVault {\n return _mint(_account, _amount);\n }\n\n /**\n * @dev Creates `_amount` tokens and assigns them to `_account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Mint to the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n _creditBalances[_account] = _creditBalances[_account].add(creditAmount);\n\n // If the account is non rebasing and doesn't have a set creditsPerToken\n // then set it i.e. this is a mint from a fresh contract\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.add(_amount);\n } else {\n rebasingCredits = rebasingCredits.add(creditAmount);\n }\n\n _totalSupply = _totalSupply.add(_amount);\n\n require(_totalSupply < MAX_SUPPLY, \"Max supply\");\n\n emit Transfer(address(0), _account, _amount);\n }\n\n /**\n * @dev Burns tokens, decreasing totalSupply.\n */\n function burn(address account, uint256 amount) external onlyVault {\n return _burn(account, amount);\n }\n\n /**\n * @dev Destroys `_amount` tokens from `_account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `_account` cannot be the zero address.\n * - `_account` must have at least `_amount` tokens.\n */\n function _burn(address _account, uint256 _amount) internal nonReentrant {\n require(_account != address(0), \"Burn from the zero address\");\n\n bool isNonRebasingAccount = _isNonRebasingAccount(_account);\n uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account));\n uint256 currentCredits = _creditBalances[_account];\n\n // Remove the credits, burning rounding errors\n if (\n currentCredits == creditAmount || currentCredits - 1 == creditAmount\n ) {\n // Handle dust from rounding\n _creditBalances[_account] = 0;\n } else if (currentCredits > creditAmount) {\n _creditBalances[_account] = _creditBalances[_account].sub(\n creditAmount\n );\n } else {\n revert(\"Remove exceeds balance\");\n }\n\n // Remove from the credit tallies and non-rebasing supply\n if (isNonRebasingAccount) {\n nonRebasingSupply = nonRebasingSupply.sub(_amount);\n } else {\n rebasingCredits = rebasingCredits.sub(creditAmount);\n }\n\n _totalSupply = _totalSupply.sub(_amount);\n\n emit Transfer(_account, address(0), _amount);\n }\n\n /**\n * @dev Get the credits per token for an account. Returns a fixed amount\n * if the account is non-rebasing.\n * @param _account Address of the account.\n */\n function _creditsPerToken(address _account)\n internal\n view\n returns (uint256)\n {\n if (nonRebasingCreditsPerToken[_account] != 0) {\n return nonRebasingCreditsPerToken[_account];\n } else {\n return rebasingCreditsPerToken;\n }\n }\n\n /**\n * @dev Is an accounts balance non rebasing, i.e. does not alter with rebases\n * @param _account Address of the account.\n */\n function _isNonRebasingAccount(address _account) internal returns (bool) {\n if (Address.isContract(_account)) {\n // Contracts by default opt out\n if (rebaseState[_account] == RebaseOptions.OptIn) {\n // If they've opted in explicitly it is not a non rebasing\n // address\n return false;\n }\n // Is a non rebasing account because no explicit opt in\n // Make sure the rebasing/non-rebasing supply is updated and\n // fixed credits per token is set for this account\n _ensureRebasingMigration(_account);\n return true;\n } else {\n // EOAs by default opt in\n // Check for explicit opt out\n return rebaseState[_account] == RebaseOptions.OptOut;\n }\n }\n\n /**\n * @dev Ensures internal account for rebasing and non-rebasing credits and\n * supply is updated following deployment of frozen yield change.\n */\n function _ensureRebasingMigration(address _account) internal {\n if (nonRebasingCreditsPerToken[_account] == 0) {\n // Set fixed credits per token for this account\n nonRebasingCreditsPerToken[_account] = rebasingCreditsPerToken;\n // Update non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account));\n // Update credit tallies\n rebasingCredits = rebasingCredits.sub(_creditBalances[_account]);\n }\n }\n\n /**\n * @dev Add a contract address to the non rebasing exception list. I.e. the\n * address's balance will be part of rebases so the account will be exposed\n * to upside and downside.\n */\n function rebaseOptIn() public nonReentrant {\n require(_isNonRebasingAccount(msg.sender), \"Account has not opted out\");\n\n // Convert balance into the same amount at the current exchange rate\n uint256 newCreditBalance = _creditBalances[msg.sender]\n .mul(rebasingCreditsPerToken)\n .div(_creditsPerToken(msg.sender));\n\n // Decreasing non rebasing supply\n nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender));\n\n _creditBalances[msg.sender] = newCreditBalance;\n\n // Increase rebasing credits, totalSupply remains unchanged so no\n // adjustment necessary\n rebasingCredits = rebasingCredits.add(_creditBalances[msg.sender]);\n\n rebaseState[msg.sender] = RebaseOptions.OptIn;\n\n // Delete any fixed credits per token\n delete nonRebasingCreditsPerToken[msg.sender];\n }\n\n /**\n * @dev Remove a contract address to the non rebasing exception list.\n */\n function rebaseOptOut() public nonReentrant {\n require(!_isNonRebasingAccount(msg.sender), \"Account has not opted in\");\n\n // Increase non rebasing supply\n nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender));\n // Set fixed credits per token\n nonRebasingCreditsPerToken[msg.sender] = rebasingCreditsPerToken;\n\n // Decrease rebasing credits, total supply remains unchanged so no\n // adjustment necessary\n rebasingCredits = rebasingCredits.sub(_creditBalances[msg.sender]);\n\n // Mark explicitly opted out of rebasing\n rebaseState[msg.sender] = RebaseOptions.OptOut;\n }\n\n /**\n * @dev Modify the supply without minting new tokens. This uses a change in\n * the exchange rate between \"credits\" and OUSD tokens to change balances.\n * @param _newTotalSupply New total supply of OUSD.\n * @return uint256 representing the new total supply.\n */\n function changeSupply(uint256 _newTotalSupply)\n external\n onlyVault\n nonReentrant\n {\n require(_totalSupply > 0, \"Cannot increase 0 supply\");\n\n if (_totalSupply == _newTotalSupply) {\n emit TotalSupplyUpdated(\n _totalSupply,\n rebasingCredits,\n rebasingCreditsPerToken\n );\n return;\n }\n\n _totalSupply = _newTotalSupply > MAX_SUPPLY\n ? MAX_SUPPLY\n : _newTotalSupply;\n\n rebasingCreditsPerToken = rebasingCredits.divPrecisely(\n _totalSupply.sub(nonRebasingSupply)\n );\n\n require(rebasingCreditsPerToken > 0, \"Invalid change in supply\");\n\n _totalSupply = rebasingCredits\n .divPrecisely(rebasingCreditsPerToken)\n .add(nonRebasingSupply);\n\n emit TotalSupplyUpdated(\n _totalSupply,\n rebasingCredits,\n rebasingCreditsPerToken\n );\n }\n}\n" + }, + "contracts/utils/InitializableERC20Detailed.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\n */\ncontract InitializableERC20Detailed is IERC20 {\n // Storage gap to skip storage from prior to OUSD reset\n uint256[100] private _____gap;\n\n string public _name;\n string public _symbol;\n uint8 public _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n * @notice To avoid variable shadowing appended `Arg` after arguments name.\n */\n function _initialize(\n string memory nameArg,\n string memory symbolArg,\n uint8 decimalsArg\n ) internal {\n _name = nameArg;\n _symbol = symbolArg;\n _decimals = decimalsArg;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Vault Admin Contract\n * @notice The VaultAdmin contract makes configuration and admin calls on the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\n\ncontract VaultAdmin is VaultStorage {\n /**\n * @dev Verifies that the caller is the Vault or Governor.\n */\n modifier onlyVaultOrGovernor() {\n require(\n msg.sender == address(this) || isGovernor(),\n \"Caller is not the Vault or Governor\"\n );\n _;\n }\n\n modifier onlyGovernorOrStrategist() {\n require(\n msg.sender == strategistAddr || isGovernor(),\n \"Caller is not the Strategist or Governor\"\n );\n _;\n }\n\n /***************************************\n Configuration\n ****************************************/\n\n /**\n * @dev Set address of price provider.\n * @param _priceProvider Address of price provider\n */\n function setPriceProvider(address _priceProvider) external onlyGovernor {\n priceProvider = _priceProvider;\n emit PriceProviderUpdated(_priceProvider);\n }\n\n /**\n * @dev Set a fee in basis points to be charged for a redeem.\n * @param _redeemFeeBps Basis point fee to be charged\n */\n function setRedeemFeeBps(uint256 _redeemFeeBps) external onlyGovernor {\n redeemFeeBps = _redeemFeeBps;\n emit RedeemFeeUpdated(_redeemFeeBps);\n }\n\n /**\n * @dev Set a buffer of assets to keep in the Vault to handle most\n * redemptions without needing to spend gas unwinding assets from a Strategy.\n * @param _vaultBuffer Percentage using 18 decimals. 100% = 1e18.\n */\n function setVaultBuffer(uint256 _vaultBuffer) external onlyGovernor {\n require(_vaultBuffer <= 1e18, \"Invalid value\");\n vaultBuffer = _vaultBuffer;\n emit VaultBufferUpdated(_vaultBuffer);\n }\n\n /**\n * @dev Sets the minimum amount of OUSD in a mint to trigger an\n * automatic allocation of funds afterwords.\n * @param _threshold OUSD amount with 18 fixed decimals.\n */\n function setAutoAllocateThreshold(uint256 _threshold)\n external\n onlyGovernor\n {\n autoAllocateThreshold = _threshold;\n emit AllocateThresholdUpdated(_threshold);\n }\n\n /**\n * @dev Set a minimum amount of OUSD in a mint or redeem that triggers a\n * rebase\n * @param _threshold OUSD amount with 18 fixed decimals.\n */\n function setRebaseThreshold(uint256 _threshold) external onlyGovernor {\n rebaseThreshold = _threshold;\n emit RebaseThresholdUpdated(_threshold);\n }\n\n /**\n * @dev Set address of Uniswap for performing liquidation of strategy reward\n * tokens\n * @param _address Address of Uniswap\n */\n function setUniswapAddr(address _address) external onlyGovernor {\n uniswapAddr = _address;\n emit UniswapUpdated(_address);\n }\n\n /**\n * @dev Set address of Strategist\n * @param _address Address of Strategist\n */\n function setStrategistAddr(address _address) external onlyGovernor {\n strategistAddr = _address;\n emit StrategistUpdated(_address);\n }\n\n /**\n * @dev Set the default Strategy for an asset, i.e. the one which the asset\n will be automatically allocated to and withdrawn from\n * @param _asset Address of the asset\n * @param _strategy Address of the Strategy\n */\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external\n onlyGovernorOrStrategist\n {\n emit AssetDefaultStrategyUpdated(_asset, _strategy);\n require(strategies[_strategy].isSupported, \"Strategy not approved\");\n IStrategy strategy = IStrategy(_strategy);\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(\n strategy.supportsAsset(_asset),\n \"Asset not supported by Strategy\"\n );\n assetDefaultStrategies[_asset] = _strategy;\n }\n\n /**\n * @dev Add a supported asset to the contract, i.e. one that can be\n * to mint OUSD.\n * @param _asset Address of asset\n */\n function supportAsset(address _asset) external onlyGovernor {\n require(!assets[_asset].isSupported, \"Asset already supported\");\n\n assets[_asset] = Asset({ isSupported: true });\n allAssets.push(_asset);\n\n emit AssetSupported(_asset);\n }\n\n /**\n * @dev Add a strategy to the Vault.\n * @param _addr Address of the strategy to add\n */\n function approveStrategy(address _addr) external onlyGovernor {\n require(!strategies[_addr].isSupported, \"Strategy already approved\");\n strategies[_addr] = Strategy({ isSupported: true, _deprecated: 0 });\n allStrategies.push(_addr);\n emit StrategyApproved(_addr);\n }\n\n /**\n * @dev Remove a strategy from the Vault. Removes all invested assets and\n * returns them to the Vault.\n * @param _addr Address of the strategy to remove\n */\n\n function removeStrategy(address _addr) external onlyGovernor {\n require(strategies[_addr].isSupported, \"Strategy not approved\");\n\n // Initialize strategyIndex with out of bounds result so function will\n // revert if no valid index found\n uint256 strategyIndex = allStrategies.length;\n for (uint256 i = 0; i < allStrategies.length; i++) {\n if (allStrategies[i] == _addr) {\n strategyIndex = i;\n break;\n }\n }\n\n if (strategyIndex < allStrategies.length) {\n allStrategies[strategyIndex] = allStrategies[allStrategies.length -\n 1];\n allStrategies.pop();\n\n // Withdraw all assets\n IStrategy strategy = IStrategy(_addr);\n strategy.withdrawAll();\n // Call harvest after withdraw in case withdraw triggers\n // distribution of additional reward tokens (true for Compound)\n _harvest(_addr);\n emit StrategyRemoved(_addr);\n }\n\n // Clean up struct in mapping, this can be removed later\n // See https://github.com/OriginProtocol/origin-dollar/issues/324\n strategies[_addr].isSupported = false;\n }\n\n /**\n * @notice Move assets from one Strategy to another\n * @param _strategyFromAddress Address of Strategy to move assets from.\n * @param _strategyToAddress Address of Strategy to move assets to.\n * @param _assets Array of asset address that will be moved\n * @param _amounts Array of amounts of each corresponding asset to move.\n */\n function reallocate(\n address _strategyFromAddress,\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external onlyGovernorOrStrategist {\n require(\n strategies[_strategyFromAddress].isSupported,\n \"Invalid from Strategy\"\n );\n require(\n strategies[_strategyToAddress].isSupported,\n \"Invalid to Strategy\"\n );\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n IStrategy strategyFrom = IStrategy(_strategyFromAddress);\n IStrategy strategyTo = IStrategy(_strategyToAddress);\n\n for (uint256 i = 0; i < _assets.length; i++) {\n require(strategyTo.supportsAsset(_assets[i]), \"Asset unsupported\");\n // Withdraw from Strategy and pass other Strategy as recipient\n strategyFrom.withdraw(address(strategyTo), _assets[i], _amounts[i]);\n // Tell new Strategy to deposit into protocol\n strategyTo.deposit(_assets[i], _amounts[i]);\n }\n }\n\n /**\n * @dev Sets the maximum allowable difference between\n * total supply and backing assets' value.\n */\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n emit MaxSupplyDiffChanged(_maxSupplyDiff);\n }\n\n /***************************************\n Pause\n ****************************************/\n\n /**\n * @dev Set the deposit paused flag to true to prevent rebasing.\n */\n function pauseRebase() external onlyGovernor {\n rebasePaused = true;\n emit RebasePaused();\n }\n\n /**\n * @dev Set the deposit paused flag to true to allow rebasing.\n */\n function unpauseRebase() external onlyGovernor {\n rebasePaused = false;\n emit RebaseUnpaused();\n }\n\n /**\n * @dev Set the deposit paused flag to true to prevent capital movement.\n */\n function pauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = true;\n emit CapitalPaused();\n }\n\n /**\n * @dev Set the deposit paused flag to false to enable capital movement.\n */\n function unpauseCapital() external onlyGovernorOrStrategist {\n capitalPaused = false;\n emit CapitalUnpaused();\n }\n\n /***************************************\n Rewards\n ****************************************/\n\n /**\n * @dev Transfer token to governor. Intended for recovering tokens stuck in\n * contract, i.e. mistaken sends.\n * @param _asset Address for the asset\n * @param _amount Amount of the asset to transfer\n */\n function transferToken(address _asset, uint256 _amount)\n external\n onlyGovernor\n {\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from all strategies and swap for supported\n * stablecoin via Uniswap\n */\n function harvest() external onlyGovernor {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n _harvest(allStrategies[i]);\n }\n }\n\n /**\n * @dev Collect reward tokens for a specific strategy and swap for supported\n * stablecoin via Uniswap\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvest(address _strategyAddr)\n external\n onlyVaultOrGovernor\n returns (uint256[] memory)\n {\n return _harvest(_strategyAddr);\n }\n\n /**\n * @dev Collect reward tokens from a single strategy and swap them for a\n * supported stablecoin via Uniswap\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function _harvest(address _strategyAddr)\n internal\n returns (uint256[] memory)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n address rewardTokenAddress = strategy.rewardTokenAddress();\n if (rewardTokenAddress != address(0)) {\n strategy.collectRewardToken();\n\n if (uniswapAddr != address(0)) {\n IERC20 rewardToken = IERC20(strategy.rewardTokenAddress());\n uint256 rewardTokenAmount = rewardToken.balanceOf(\n address(this)\n );\n if (rewardTokenAmount > 0) {\n // Give Uniswap full amount allowance\n rewardToken.safeApprove(uniswapAddr, 0);\n rewardToken.safeApprove(uniswapAddr, rewardTokenAmount);\n\n // Uniswap redemption path\n address[] memory path = new address[](3);\n path[0] = strategy.rewardTokenAddress();\n path[1] = IUniswapV2Router(uniswapAddr).WETH();\n path[2] = allAssets[1]; // USDT\n\n return\n IUniswapV2Router(uniswapAddr).swapExactTokensForTokens(\n rewardTokenAmount,\n uint256(0),\n path,\n address(this),\n now.add(1800)\n );\n }\n }\n }\n }\n\n /***************************************\n Pricing\n ****************************************/\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Min since min is what we use for mint pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function priceUSDMint(string calldata symbol)\n external\n view\n returns (uint256)\n {\n return _priceUSDMint(symbol);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Min since min is what we use for mint pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function _priceUSDMint(string memory symbol)\n internal\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return IMinMaxOracle(priceProvider).priceMin(symbol).scaleBy(10);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Max since max is what we use for redeem pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function priceUSDRedeem(string calldata symbol)\n external\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return _priceUSDRedeem(symbol);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Using Max since max is what we use for redeem pricing\n * @param symbol String symbol of the asset\n * @return uint256 USD price of 1 of the asset\n */\n function _priceUSDRedeem(string memory symbol)\n internal\n view\n returns (uint256)\n {\n // Price from Oracle is returned with 8 decimals\n // scale to 18 so 18-8=10\n return IMinMaxOracle(priceProvider).priceMax(symbol).scaleBy(10);\n }\n}\n" + }, + "contracts/interfaces/IMinMaxOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IMinMaxOracle {\n //Assuming 8 decimals\n function priceMin(string calldata symbol) external view returns (uint256);\n\n function priceMax(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IUniswapV2Router {\n function WETH() external pure returns (address);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockUniswapRouter is IUniswapV2Router {\n using StableMath for uint256;\n\n address tok0;\n address tok1;\n\n address public WETH = address(0);\n\n function initialize(address _token0, address _token1) public {\n tok0 = _token0;\n tok1 = _token1;\n }\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts) {\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n IERC20(tok1).transfer(\n to,\n amountIn.scaleBy(\n int8(Helpers.getDecimals(tok1) - Helpers.getDecimals(tok0))\n )\n );\n }\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n )\n {\n // this is needed to make this contract whole else it'd be just virtual\n }\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "pragma solidity 0.5.11;\npragma experimental ABIEncoderV2;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract SingleAssetStaking is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n /* ========== STATE VARIABLES ========== */\n\n IERC20 public stakingToken; // this is both the staking and rewards\n\n struct Stake {\n uint256 amount; // amount to stake\n uint256 end; // when does the staking period end\n uint256 duration; // the duration of the stake\n uint240 rate; // rate to charge use 248 to reserve 8 bits for the bool\n bool paid;\n uint8 stakeType;\n }\n\n struct DropRoot {\n bytes32 hash;\n uint256 depth;\n }\n\n uint256[] public durations; // allowed durations\n uint256[] public rates; // rates that correspond with the allowed durations\n\n uint256 public totalOutstanding;\n bool public paused;\n\n mapping(address => Stake[]) public userStakes;\n\n mapping(uint8 => DropRoot) public dropRoots;\n\n // type 0 is reserved for stakes done by the user, all other types will be drop/preApproved stakes\n uint8 constant USER_STAKE_TYPE = 0;\n uint256 constant MAX_STAKES = 256;\n\n /* ========== Initialize ========== */\n\n /**\n * @dev Initialize the contracts, sets up durations, rates, and preApprover\n * for preApproved contracts can only be called once\n * @param _stakingToken Address of the token that we are staking\n * @param _durations Array of allowed durations in seconds\n * @param _rates Array of rates(0.3 is 30%) that correspond to the allowed\n * durations in 1e18 precision\n */\n function initialize(\n address _stakingToken,\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor initializer {\n stakingToken = IERC20(_stakingToken);\n _setDurationRates(_durations, _rates);\n }\n\n /* ========= Internal helper functions ======== */\n\n /**\n * @dev Validate and set the duration and corresponding rates, will emit\n * events NewRate and NewDurations\n */\n function _setDurationRates(\n uint256[] memory _durations,\n uint256[] memory _rates\n ) internal {\n require(\n _rates.length == _durations.length,\n \"Mismatch durations and rates\"\n );\n\n for (uint256 i = 0; i < _rates.length; i++) {\n require(_rates[i] < uint240(-1), \"Max rate exceeded\");\n }\n\n rates = _rates;\n durations = _durations;\n\n emit NewRates(msg.sender, rates);\n emit NewDurations(msg.sender, durations);\n }\n\n function _totalExpectedRewards(Stake[] storage stakes)\n internal\n view\n returns (uint256 total)\n {\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (!stake.paid) {\n total = total.add(stake.amount.mulTruncate(stake.rate));\n }\n }\n }\n\n function _totalExpected(Stake storage _stake)\n internal\n view\n returns (uint256)\n {\n return _stake.amount.add(_stake.amount.mulTruncate(_stake.rate));\n }\n\n function _airDroppedStakeClaimed(address account, uint8 stakeType)\n internal\n view\n returns (bool)\n {\n Stake[] storage stakes = userStakes[account];\n for (uint256 i = 0; i < stakes.length; i++) {\n if (stakes[i].stakeType == stakeType) {\n return true;\n }\n }\n return false;\n }\n\n function _findDurationRate(uint256 duration)\n internal\n view\n returns (uint240)\n {\n for (uint256 i = 0; i < durations.length; i++) {\n if (duration == durations[i]) {\n return uint240(rates[i]);\n }\n }\n return 0;\n }\n\n /**\n * @dev Internal staking function\n * will insert the stake into the stakes array and verify we have\n * enough to pay off stake + reward\n * @param staker Address of the staker\n * @param stakeType Number that represent the type of the stake, 0 is user\n * initiated all else is currently preApproved\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 =\n * to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n */\n function _stake(\n address staker,\n uint8 stakeType,\n uint256 duration,\n uint240 rate,\n uint256 amount\n ) internal {\n require(!paused, \"Staking paused\");\n\n Stake[] storage stakes = userStakes[staker];\n\n uint256 end = block.timestamp.add(duration);\n\n uint256 i = stakes.length; // start at the end of the current array\n\n require(i < MAX_STAKES, \"Max stakes\");\n\n stakes.length += 1; // grow the array\n // find the spot where we can insert the current stake\n // this should make an increasing list sorted by end\n while (i != 0 && stakes[i - 1].end > end) {\n // shift it back one\n stakes[i] = stakes[i - 1];\n i -= 1;\n }\n\n // insert the stake\n Stake storage newStake = stakes[i];\n newStake.rate = rate;\n newStake.stakeType = stakeType;\n newStake.end = end;\n newStake.duration = duration;\n newStake.amount = amount;\n\n totalOutstanding = totalOutstanding.add(_totalExpected(newStake));\n\n emit Staked(staker, amount, duration, rate);\n }\n\n function _stakeWithChecks(\n address staker,\n uint256 amount,\n uint256 duration\n ) internal {\n require(amount > 0, \"Cannot stake 0\");\n\n uint240 rewardRate = _findDurationRate(duration);\n require(rewardRate > 0, \"Invalid duration\"); // we couldn't find the rate that correspond to the passed duration\n\n _stake(staker, USER_STAKE_TYPE, duration, rewardRate, amount);\n // transfer in the token so that we can stake the correct amount\n stakingToken.safeTransferFrom(staker, address(this), amount);\n }\n\n modifier requireLiquidity() {\n // we need to have enough balance to cover the rewards after the operation is complete\n _;\n require(\n stakingToken.balanceOf(address(this)) >= totalOutstanding,\n \"Insufficient rewards\"\n );\n }\n\n /* ========== VIEWS ========== */\n\n function getAllDurations() external view returns (uint256[] memory) {\n return durations;\n }\n\n function getAllRates() external view returns (uint256[] memory) {\n return rates;\n }\n\n /**\n * @dev Return all the stakes paid and unpaid for a given user\n * @param account Address of the account that we want to look up\n */\n function getAllStakes(address account)\n external\n view\n returns (Stake[] memory)\n {\n return userStakes[account];\n }\n\n /**\n * @dev Find the rate that corresponds to a given duration\n * @param _duration Number of seconds\n */\n function durationRewardRate(uint256 _duration)\n external\n view\n returns (uint256)\n {\n return _findDurationRate(_duration);\n }\n\n /**\n * @dev Has the airdropped stake already been claimed\n */\n function airDroppedStakeClaimed(address account, uint8 stakeType)\n external\n view\n returns (bool)\n {\n return _airDroppedStakeClaimed(account, stakeType);\n }\n\n /**\n * @dev Calculate all the staked value a user has put into the contract,\n * rewards not included\n * @param account Address of the account that we want to look up\n */\n function totalStaked(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n if (!stakes[i].paid) {\n total = total.add(stakes[i].amount);\n }\n }\n }\n\n /**\n * @dev Calculate all the rewards a user can expect to receive.\n * @param account Address of the account that we want to look up\n */\n function totalExpectedRewards(address account)\n external\n view\n returns (uint256)\n {\n return _totalExpectedRewards(userStakes[account]);\n }\n\n /**\n * @dev Calculate all current holdings of a user: staked value + prorated rewards\n * @param account Address of the account that we want to look up\n */\n function totalCurrentHoldings(address account)\n external\n view\n returns (uint256 total)\n {\n Stake[] storage stakes = userStakes[account];\n\n for (uint256 i = 0; i < stakes.length; i++) {\n Stake storage stake = stakes[i];\n if (stake.paid) {\n continue;\n } else if (stake.end < block.timestamp) {\n total = total.add(_totalExpected(stake));\n } else {\n //calcualte the precentage accrued in term of rewards\n total = total.add(\n stake.amount.add(\n stake.amount.mulTruncate(stake.rate).mulTruncate(\n stake\n .duration\n .sub(stake.end.sub(block.timestamp))\n .divPrecisely(stake.duration)\n )\n )\n );\n }\n }\n }\n\n /* ========== MUTATIVE FUNCTIONS ========== */\n\n /**\n * @dev Make a preapproved stake for the user, this is a presigned voucher that the user can redeem either from\n * an airdrop or a compensation program.\n * Only 1 of each type is allowed per user. The proof must match the root hash\n * @param index Number that is zero base index of the stake in the payout entry\n * @param stakeType Number that represent the type of the stake, must not be 0 which is user stake\n * @param duration Number of seconds this stake will be held for\n * @param rate Rate(0.3 is 30%) of reward for this stake in 1e18, uint240 to fit the bool and type in struct Stake\n * @param amount Number of tokens to stake in 1e18\n * @param merkleProof Array of proofs for that amount\n */\n function airDroppedStake(\n uint256 index,\n uint8 stakeType,\n uint256 duration,\n uint256 rate,\n uint256 amount,\n bytes32[] calldata merkleProof\n ) external requireLiquidity {\n require(stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n require(rate < uint240(-1), \"Max rate exceeded\");\n require(index < 2**merkleProof.length, \"Invalid index\");\n DropRoot storage dropRoot = dropRoots[stakeType];\n require(merkleProof.length == dropRoot.depth, \"Invalid proof\");\n\n // Compute the merkle root\n bytes32 node = keccak256(\n abi.encodePacked(\n index,\n stakeType,\n address(this),\n msg.sender,\n duration,\n rate,\n amount\n )\n );\n uint256 path = index;\n for (uint16 i = 0; i < merkleProof.length; i++) {\n if ((path & 0x01) == 1) {\n node = keccak256(abi.encodePacked(merkleProof[i], node));\n } else {\n node = keccak256(abi.encodePacked(node, merkleProof[i]));\n }\n path /= 2;\n }\n\n // Check the merkle proof\n require(node == dropRoot.hash, \"Stake not approved\");\n\n // verify that we haven't already staked\n require(\n !_airDroppedStakeClaimed(msg.sender, stakeType),\n \"Already staked\"\n );\n\n _stake(msg.sender, stakeType, duration, uint240(rate), amount);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract.\n * User must have already approved the contract for specified amount.\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stake(uint256 amount, uint256 duration) external requireLiquidity {\n // no checks are performed in this function since those are already present in _stakeWithChecks\n _stakeWithChecks(msg.sender, amount, duration);\n }\n\n /**\n * @dev Stake an approved amount of staking token into the contract. This function\n * can only be called by OGN token contract.\n * @param staker Address of the account that is creating the stake\n * @param amount Number of tokens to stake in 1e18\n * @param duration Number of seconds this stake will be held for\n */\n function stakeWithSender(\n address staker,\n uint256 amount,\n uint256 duration\n ) external returns (bool) {\n require(\n msg.sender == address(stakingToken),\n \"Only token contract can make this call\"\n );\n\n _stakeWithChecks(staker, amount, duration);\n return true;\n }\n\n /**\n * @dev Exit out of all possible stakes\n */\n function exit() external requireLiquidity {\n Stake[] storage stakes = userStakes[msg.sender];\n require(stakes.length > 0, \"Nothing staked\");\n\n uint256 totalWithdraw = 0;\n uint256 stakedAmount = 0;\n uint256 l = stakes.length;\n do {\n Stake storage exitStake = stakes[l - 1];\n // stop on the first ended stake that's already been paid\n if (exitStake.end < block.timestamp && exitStake.paid) {\n break;\n }\n //might not be ended\n if (exitStake.end < block.timestamp) {\n //we are paying out the stake\n exitStake.paid = true;\n totalWithdraw = totalWithdraw.add(_totalExpected(exitStake));\n stakedAmount = stakedAmount.add(exitStake.amount);\n }\n l--;\n } while (l > 0);\n require(totalWithdraw > 0, \"All stakes in lock-up\");\n\n totalOutstanding = totalOutstanding.sub(totalWithdraw);\n emit Withdrawn(msg.sender, totalWithdraw, stakedAmount);\n stakingToken.safeTransfer(msg.sender, totalWithdraw);\n }\n\n /* ========== MODIFIERS ========== */\n\n function setPaused(bool _paused) external onlyGovernor {\n paused = _paused;\n emit Paused(msg.sender, paused);\n }\n\n /**\n * @dev Set new durations and rates will not effect existing stakes\n * @param _durations Array of durations in seconds\n * @param _rates Array of rates that corresponds to the durations (0.01 is 1%) in 1e18\n */\n function setDurationRates(\n uint256[] calldata _durations,\n uint256[] calldata _rates\n ) external onlyGovernor {\n _setDurationRates(_durations, _rates);\n }\n\n /**\n * @dev Set air drop root for a specific stake type\n * @param _stakeType Type of staking must be greater than 0\n * @param _rootHash Root hash of the Merkle Tree\n * @param _proofDepth Depth of the Merklke Tree\n */\n function setAirDropRoot(\n uint8 _stakeType,\n bytes32 _rootHash,\n uint256 _proofDepth\n ) external onlyGovernor {\n require(_stakeType != USER_STAKE_TYPE, \"Cannot be normal staking\");\n dropRoots[_stakeType].hash = _rootHash;\n dropRoots[_stakeType].depth = _proofDepth;\n emit NewAirDropRootHash(_stakeType, _rootHash, _proofDepth);\n }\n\n /* ========== EVENTS ========== */\n\n event Staked(\n address indexed user,\n uint256 amount,\n uint256 duration,\n uint256 rate\n );\n event Withdrawn(address indexed user, uint256 amount, uint256 stakedAmount);\n event Paused(address indexed user, bool yes);\n event NewDurations(address indexed user, uint256[] durations);\n event NewRates(address indexed user, uint256[] rates);\n event NewAirDropRootHash(\n uint8 stakeType,\n bytes32 rootHash,\n uint256 proofDepth\n );\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n IAaveAToken,\n IAaveLendingPool,\n ILendingPoolAddressesProvider\n} from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\nimport {\n IERC20,\n ERC20,\n ERC20Mintable\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport {\n ERC20Detailed\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\n// 1. User calls 'getLendingPool'\n// 2. User calls 'deposit' (Aave)\n// - Deposit their underlying\n// - Mint aToken to them\n// 3. User calls redeem (aToken)\n// - Retrieve their aToken\n// - Return equal amount of underlying\n\ncontract MockAToken is ERC20Mintable, ERC20Detailed {\n address public lendingPool;\n IERC20 public underlyingToken;\n using SafeERC20 for IERC20;\n\n constructor(\n address _lendingPool,\n string memory _name,\n string memory _symbol,\n IERC20 _underlyingToken\n )\n public\n ERC20Detailed(\n _name,\n _symbol,\n ERC20Detailed(address(_underlyingToken)).decimals()\n )\n {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n addMinter(_lendingPool);\n }\n\n function redeem(uint256 _amount) external {\n // Redeem these a Tokens\n _burn(msg.sender, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, msg.sender, _amount);\n }\n}\n\ncontract MockAave is IAaveLendingPool, ILendingPoolAddressesProvider {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n mapping(address => address) reserveToAToken;\n address pool = address(this);\n address payable core = address(uint160(address(this)));\n uint256 factor;\n\n function addAToken(address _aToken, address _underlying) public {\n IERC20(_underlying).safeApprove(_aToken, 0);\n IERC20(_underlying).safeApprove(_aToken, uint256(-1));\n reserveToAToken[_underlying] = _aToken;\n }\n\n // set the reserve factor / basically the interest on deposit\n // in 18 precision\n // so 0.5% would be 5 * 10 ^ 15\n function setFactor(uint256 factor_) public {\n factor = factor_;\n }\n\n function deposit(\n address _reserve,\n uint256 _amount,\n uint16 /*_referralCode*/\n ) external {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n ERC20Mintable(reserveToAToken[_reserve]).mint(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n ERC20Mintable(reserveToAToken[_reserve]).mint(msg.sender, _amount);\n }\n\n function getLendingPool() external view returns (address) {\n return pool;\n }\n\n function getLendingPoolCore() external view returns (address payable) {\n return core;\n }\n}\n" + }, + "contracts/strategies/IAave.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @dev Interface for Aaves A Token\n * Documentation: https://developers.aave.com/#atokens\n */\ninterface IAaveAToken {\n /**\n * @notice Non-standard ERC20 function to redeem an _amount of aTokens for the underlying\n * asset, burning the aTokens during the process.\n * @param _amount Amount of aTokens\n */\n function redeem(uint256 _amount) external;\n\n /**\n * @notice returns the current total aToken balance of _user all interest collected included.\n * To obtain the user asset principal balance with interests excluded , ERC20 non-standard\n * method principalBalanceOf() can be used.\n */\n function balanceOf(address _user) external view returns (uint256);\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpool\n */\ninterface IAaveLendingPool {\n /**\n * @notice Deposits a certain _amount of an asset specified by the _reserve parameter.\n * @dev The caller receives a certain amount of corresponding aTokens in exchange.\n * The amount of aTokens received depends on the corresponding aToken exchange rate.\n * LendingPoolCore must be approved to spend this reserve\n */\n function deposit(\n address _reserve,\n uint256 _amount,\n uint16 _referralCode\n ) external;\n}\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpooladdressesprovider\n */\ninterface ILendingPoolAddressesProvider {\n /**\n * @notice Get the current address for Aave LendingPool\n * @dev Lending pool is the core contract on which to call deposit\n */\n function getLendingPool() external view returns (address);\n\n /**\n * @notice Get the address for lendingPoolCore\n * @dev IMPORTANT - this is where _reserve must be approved before deposit\n */\n function getLendingPoolCore() external view returns (address payable);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./ERC20.sol\";\nimport \"../../access/roles/MinterRole.sol\";\n\n/**\n * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},\n * which have permission to mint (create) new tokens as they see fit.\n *\n * At construction, the deployer of the contract is the only minter.\n */\ncontract ERC20Mintable is ERC20, MinterRole {\n /**\n * @dev See {ERC20-_mint}.\n *\n * Requirements:\n *\n * - the caller must have the {MinterRole}.\n */\n function mint(address account, uint256 amount) public onlyMinter returns (bool) {\n _mint(account, amount);\n return true;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20 {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor (string memory name, string memory symbol, uint8 decimals) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./IERC20.sol\";\nimport \"../../math/SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20 {\n using SafeMath for uint256;\n\n mapping (address => uint256) private _balances;\n\n mapping (address => mapping (address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, \"ERC20: transfer amount exceeds allowance\"));\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, \"ERC20: decreased allowance below zero\"));\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(address sender, address recipient, uint256 amount) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(amount, \"ERC20: transfer amount exceeds balance\");\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\"));\n }\n}\n" + }, + "@openzeppelin/contracts/access/roles/MinterRole.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"../Roles.sol\";\n\ncontract MinterRole is Context {\n using Roles for Roles.Role;\n\n event MinterAdded(address indexed account);\n event MinterRemoved(address indexed account);\n\n Roles.Role private _minters;\n\n constructor () internal {\n _addMinter(_msgSender());\n }\n\n modifier onlyMinter() {\n require(isMinter(_msgSender()), \"MinterRole: caller does not have the Minter role\");\n _;\n }\n\n function isMinter(address account) public view returns (bool) {\n return _minters.has(account);\n }\n\n function addMinter(address account) public onlyMinter {\n _addMinter(account);\n }\n\n function renounceMinter() public {\n _removeMinter(_msgSender());\n }\n\n function _addMinter(address account) internal {\n _minters.add(account);\n emit MinterAdded(account);\n }\n\n function _removeMinter(address account) internal {\n _minters.remove(account);\n emit MinterRemoved(account);\n }\n}\n" + }, + "@openzeppelin/contracts/GSN/Context.sol": { + "content": "pragma solidity ^0.5.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor () internal { }\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/access/Roles.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @title Roles\n * @dev Library for managing addresses assigned to a Role.\n */\nlibrary Roles {\n struct Role {\n mapping (address => bool) bearer;\n }\n\n /**\n * @dev Give an account access to this role.\n */\n function add(Role storage role, address account) internal {\n require(!has(role, account), \"Roles: account already has role\");\n role.bearer[account] = true;\n }\n\n /**\n * @dev Remove an account's access to this role.\n */\n function remove(Role storage role, address account) internal {\n require(has(role, account), \"Roles: account does not have role\");\n role.bearer[account] = false;\n }\n\n /**\n * @dev Check if an account has this role.\n * @return bool\n */\n function has(Role storage role, address account) internal view returns (bool) {\n require(account != address(0), \"Roles: account is the zero address\");\n return role.bearer[account];\n }\n}\n" + }, + "contracts/mocks/MockOGN.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\nimport \"./WhitelistedPausableToken.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting, burning, and pausing by contract owner.\n * @dev Important note:\n * @dev There is a known race condition in the ERC20 standard on the approve() method.\n * @dev See details: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * @dev The Origin token contract implements the increaseApproval() and decreaseApproval() methods.\n * @dev It is strongly recommended to use those methods rather than approve()\n * @dev when updating the token allowance.\n */\n// Removed ERC20Mintable since this is a Mock and we're just exposing the mint function directly\ncontract MockOGN is ERC20Burnable, WhitelistedPausableToken, ERC20Detailed {\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n\n // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply)\n public\n ERC20Detailed(\"OriginToken\", \"OGN\", 18)\n {\n owner = msg.sender;\n _mint(owner, _initialSupply);\n }\n\n // @dev Helper method for mocks testing to allow tests to quickly fund users\n // @param _value Amount of token to be created\n function mint(uint256 _value) external returns (bool) {\n _mint(msg.sender, _value);\n return true;\n }\n\n //\n // Burn methods\n //\n\n // @dev Burns tokens belonging to the sender\n // @param _value Amount of token to be burned\n function burn(uint256 _value) public onlyOwner {\n // TODO: add a function & modifier to enable for all accounts without doing\n // a contract migration?\n super.burn(_value);\n }\n\n // @dev Burns tokens belonging to the specified address\n // @param _who The account whose tokens we're burning\n // @param _value Amount of token to be burned\n function burn(address _who, uint256 _value) public onlyOwner {\n _burn(_who, _value);\n }\n\n //\n // approveAndCall methods\n //\n\n // @dev Add spender to whitelist of spenders for approveAndCall\n // @param _spender Address to add\n function addCallSpenderWhitelist(address _spender) public onlyOwner {\n callSpenderWhitelist[_spender] = true;\n emit AddCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Remove spender from whitelist of spenders for approveAndCall\n // @param _spender Address to remove\n function removeCallSpenderWhitelist(address _spender) public onlyOwner {\n delete callSpenderWhitelist[_spender];\n emit RemoveCallSpenderWhitelist(msg.sender, _spender);\n }\n\n // @dev Approve transfer of tokens and make a contract call in a single\n // @dev transaction. This allows a DApp to avoid requiring two MetaMask\n // @dev approvals for a single logical action, such as creating a listing,\n // @dev which requires the seller to approve a token transfer and the\n // @dev marketplace contract to transfer tokens from the seller.\n //\n // @dev This is based on the ERC827 function approveAndCall and avoids\n // @dev security issues by only working with a whitelisted set of _spender\n // @dev addresses. The other difference is that the combination of this\n // @dev function ensures that the proxied function call receives the\n // @dev msg.sender for this function as its first parameter.\n //\n // @param _spender The address that will spend the funds.\n // @param _value The amount of tokens to be spent.\n // @param _selector Function selector for function to be called.\n // @param _callParams Packed, encoded parameters, omitting the first parameter which is always msg.sender\n function approveAndCallWithSender(\n address _spender,\n uint256 _value,\n bytes4 _selector,\n bytes memory _callParams\n ) public payable returns (bool) {\n require(_spender != address(this), \"token contract can't be approved\");\n require(callSpenderWhitelist[_spender], \"spender not in whitelist\");\n\n require(super.approve(_spender, _value), \"approve failed\");\n\n bytes memory callData = abi.encodePacked(\n _selector,\n uint256(msg.sender),\n _callParams\n );\n // solium-disable-next-line security/no-call-value\n (bool success, ) = _spender.call.value(msg.value)(callData);\n require(success, \"proxied call failed\");\n return true;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"./ERC20.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\ncontract ERC20Burnable is Context, ERC20 {\n /**\n * @dev Destroys `amount` tokens from the caller.\n *\n * See {ERC20-_burn}.\n */\n function burn(uint256 amount) public {\n _burn(_msgSender(), amount);\n }\n\n /**\n * @dev See {ERC20-_burnFrom}.\n */\n function burnFrom(address account, uint256 amount) public {\n _burnFrom(account, amount);\n }\n}\n" + }, + "contracts/mocks/WhitelistedPausableToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol\";\n\n/**\n * @title Contract for enforcing a list of addresses allowed to send or receive tokens\n * @dev Until the whitelist expiration expires, this contract only permits\n * token transfers in which an allowed transactor is either the sender or\n * recipient. Once the whitelist expiration passes, it becomes impossible to\n * re-enable the whitelist.\n *\n * This contract inherits from ERC20Pausable to enforce both pausing and\n * whitelists for transfer calls.\n */\ncontract WhitelistedPausableToken is ERC20Pausable {\n address public owner = msg.sender;\n\n // UNIX timestamp (in seconds) after which this whitelist no longer applies\n uint256 public whitelistExpiration;\n // While the whitelist is active, either the sender or recipient must be\n // in allowedTransactors.\n mapping(address => bool) public allowedTransactors;\n\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n\n //\n // Functions for maintaining whitelist\n //\n\n modifier onlyOwner {\n require(msg.sender == owner);\n _;\n }\n modifier allowedTransfer(address _from, address _to) {\n require(\n // solium-disable-next-line operator-whitespace\n !whitelistActive() ||\n allowedTransactors[_from] ||\n allowedTransactors[_to],\n \"neither sender nor recipient are allowed\"\n );\n _;\n }\n\n function whitelistActive() public view returns (bool) {\n return block.timestamp < whitelistExpiration;\n }\n\n function addAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorAdded(_transactor);\n allowedTransactors[_transactor] = true;\n }\n\n function removeAllowedTransactor(address _transactor) public onlyOwner {\n emit AllowedTransactorRemoved(_transactor);\n delete allowedTransactors[_transactor];\n }\n\n /**\n * @dev Set the whitelist expiration, after which the whitelist no longer\n * applies.\n */\n function setWhitelistExpiration(uint256 _expiration) public onlyOwner {\n // allow only if whitelist expiration hasn't yet been set, or if the\n // whitelist expiration hasn't passed yet\n require(\n whitelistExpiration == 0 || whitelistActive(),\n \"an expired whitelist cannot be extended\"\n );\n // prevent possible mistakes in calling this function\n require(\n _expiration >= block.timestamp + 1 days,\n \"whitelist expiration not far enough into the future\"\n );\n emit SetWhitelistExpiration(_expiration);\n whitelistExpiration = _expiration;\n }\n\n //\n // ERC20 transfer functions that have been overridden to enforce the\n // whitelist.\n //\n\n function transfer(address _to, uint256 _value)\n public\n allowedTransfer(msg.sender, _to)\n returns (bool)\n {\n return super.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./ERC20.sol\";\nimport \"../../lifecycle/Pausable.sol\";\n\n/**\n * @title Pausable token\n * @dev ERC20 with pausable transfers and allowances.\n *\n * Useful if you want to stop trades until the end of a crowdsale, or have\n * an emergency switch for freezing all token transfers in the event of a large\n * bug.\n */\ncontract ERC20Pausable is ERC20, Pausable {\n function transfer(address to, uint256 value) public whenNotPaused returns (bool) {\n return super.transfer(to, value);\n }\n\n function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {\n return super.transferFrom(from, to, value);\n }\n\n function approve(address spender, uint256 value) public whenNotPaused returns (bool) {\n return super.approve(spender, value);\n }\n\n function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) {\n return super.increaseAllowance(spender, addedValue);\n }\n\n function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) {\n return super.decreaseAllowance(spender, subtractedValue);\n }\n}\n" + }, + "@openzeppelin/contracts/lifecycle/Pausable.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../GSN/Context.sol\";\nimport \"../access/roles/PauserRole.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\ncontract Pausable is Context, PauserRole {\n /**\n * @dev Emitted when the pause is triggered by a pauser (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by a pauser (`account`).\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state. Assigns the Pauser role\n * to the deployer.\n */\n constructor () internal {\n _paused = false;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by a pauser to pause, triggers stopped state.\n */\n function pause() public onlyPauser whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by a pauser to unpause, returns to normal state.\n */\n function unpause() public onlyPauser whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/access/roles/PauserRole.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"../../GSN/Context.sol\";\nimport \"../Roles.sol\";\n\ncontract PauserRole is Context {\n using Roles for Roles.Role;\n\n event PauserAdded(address indexed account);\n event PauserRemoved(address indexed account);\n\n Roles.Role private _pausers;\n\n constructor () internal {\n _addPauser(_msgSender());\n }\n\n modifier onlyPauser() {\n require(isPauser(_msgSender()), \"PauserRole: caller does not have the Pauser role\");\n _;\n }\n\n function isPauser(address account) public view returns (bool) {\n return _pausers.has(account);\n }\n\n function addPauser(address account) public onlyPauser {\n _addPauser(account);\n }\n\n function renouncePauser() public {\n _removePauser(_msgSender());\n }\n\n function _addPauser(address account) internal {\n _pausers.add(account);\n emit PauserAdded(account);\n }\n\n function _removePauser(address account) internal {\n _pausers.remove(account);\n emit PauserRemoved(account);\n }\n}\n" + }, + "contracts/mocks/MockCToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n IERC20,\n ERC20,\n ERC20Mintable\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol\";\nimport {\n ERC20Detailed\n} from \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20, ERC20Detailed, ERC20Mintable {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n\n constructor(ERC20Detailed _underlyingToken)\n public\n ERC20Detailed(\"cMock\", \"cMK\", 8)\n {\n uint8 underlyingDecimals = _underlyingToken.decimals();\n // if has 18 dp, exchange rate should be 1e26\n // if has 8 dp, exchange rate should be 1e18\n if (underlyingDecimals > 8) {\n exchangeRate = 10**uint256(18 + underlyingDecimals - 10);\n } else if (underlyingDecimals < 8) {\n // e.g. 18-8+6 = 16\n exchangeRate = 10**uint256(18 - 8 + underlyingDecimals);\n } else {\n exchangeRate = 1e18;\n }\n underlyingToken = _underlyingToken;\n }\n\n function mint(uint256 mintAmount) external returns (uint256) {\n // Credit them with cToken\n _mint(msg.sender, mintAmount.divPrecisely(exchangeRate));\n // Take their reserve\n underlyingToken.transferFrom(msg.sender, address(this), mintAmount);\n return 0;\n }\n\n function redeem(uint256 redeemAmount) external returns (uint256) {\n uint256 tokenAmount = redeemAmount.mulTruncate(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, redeemAmount);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, tokenAmount);\n return 0;\n }\n\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256) {\n uint256 cTokens = redeemAmount.divPrecisely(exchangeRate);\n // Burn the cToken\n _burn(msg.sender, cTokens);\n // Transfer underlying to caller\n underlyingToken.transfer(msg.sender, redeemAmount);\n return 0;\n }\n\n function balanceOfUnderlying(address owner) external returns (uint256) {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function updateExchangeRate() internal returns (uint256) {\n uint256 factor = 100002 * (10**13); // 0.002%\n exchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external view returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "contracts/strategies/ICompound.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @dev Compound C Token interface\n * Documentation: https://compound.finance/developers/ctokens\n */\ninterface ICERC20 {\n /**\n * @notice The mint function transfers an asset into the protocol, which begins accumulating\n * interest based on the current Supply Rate for the asset. The user receives a quantity of\n * cTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.\n * @param mintAmount The amount of the asset to be supplied, in units of the underlying asset.\n * @return 0 on success, otherwise an Error codes\n */\n function mint(uint256 mintAmount) external returns (uint256);\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise an error code.\n */\n function redeem(uint256 redeemTokens) external returns (uint256);\n\n /**\n * @notice The redeem underlying function converts cTokens into a specified quantity of the underlying\n * asset, and returns them to the user. The amount of cTokens redeemed is equal to the quantity of\n * underlying tokens received, divided by the current Exchange Rate. The amount redeemed must be less\n * than the user's Account Liquidity and the market's available liquidity.\n * @param redeemAmount The amount of underlying to be redeemed.\n * @return 0 on success, otherwise an error code.\n */\n function redeemUnderlying(uint256 redeemAmount) external returns (uint256);\n\n /**\n * @notice The user's underlying balance, representing their assets in the protocol, is equal to\n * the user's cToken balance multiplied by the Exchange Rate.\n * @param owner The account to get the underlying balance of.\n * @return The amount of underlying currently owned by the account.\n */\n function balanceOfUnderlying(address owner) external returns (uint256);\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view returns (uint256);\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @notice Get the supply rate per block for supplying the token to Compound.\n */\n function supplyRatePerBlock() external view returns (uint256);\n}\n" + }, + "contracts/strategies/CompoundStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Compound Strategy\n * @notice Investment strategy for investing stablecoins via Compound\n * @author Origin Protocol Inc\n */\nimport { ICERC20 } from \"./ICompound.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is InitializableAbstractStrategy {\n event SkippedWithdrawal(address asset, uint256 amount);\n\n /**\n * @dev Deposit asset into Compound\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n * @return amountDeposited Amount of asset that was deposited\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n emit Deposit(_asset, address(cToken), _amount);\n require(cToken.mint(_amount) == 0, \"cToken mint failed\");\n }\n\n /**\n * @dev Withdraw asset from Compound\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n * @return amountWithdrawn Amount of asset that was withdrawn\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n ICERC20 cToken = _getCTokenFor(_asset);\n // If redeeming 0 cTokens, just skip, else COMP will revert\n uint256 cTokensToRedeem = _convertUnderlyingToCToken(cToken, _amount);\n if (cTokensToRedeem == 0) {\n emit SkippedWithdrawal(_asset, _amount);\n return;\n }\n\n emit Withdrawal(_asset, address(cToken), _amount);\n require(cToken.redeemUnderlying(_amount) == 0, \"Redeem failed\");\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of cToken\n ICERC20 cToken = _getCTokenFor(assetsMapped[i]);\n if (cToken.balanceOf(address(this)) > 0) {\n require(\n cToken.redeem(cToken.balanceOf(address(this))) == 0,\n \"Redeem failed\"\n );\n // Transfer entire balance to Vault\n IERC20 asset = IERC20(assetsMapped[i]);\n asset.safeTransfer(\n vaultAddress,\n asset.balanceOf(address(this))\n );\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * This includes any interest that was generated since depositing\n * Compound exchange rate between the cToken and asset gradually increases,\n * causing the cToken to be worth more corresponding asset.\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // Balance is always with token cToken decimals\n ICERC20 cToken = _getCTokenFor(_asset);\n balance = _checkBalance(cToken);\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * underlying = (cTokenAmt * exchangeRate) / 1e18\n * @param _cToken cToken for which to check balance\n * @return balance Total value of the asset in the platform\n */\n function _checkBalance(ICERC20 _cToken)\n internal\n view\n returns (uint256 balance)\n {\n uint256 cTokenBalance = _cToken.balanceOf(address(this));\n uint256 exchangeRate = _cToken.exchangeRateStored();\n // e.g. 50e8*205316390724364402565641705 / 1e18 = 1.0265..e18\n balance = cTokenBalance.mul(exchangeRate).div(1e18);\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding cToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external {\n uint256 assetCount = assetsMapped.length;\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n address cToken = assetToPToken[asset];\n // Safe approval\n IERC20(asset).safeApprove(cToken, 0);\n IERC20(asset).safeApprove(cToken, uint256(-1));\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / cTokens\n * We need to approve the cToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve\n * @param _cToken This cToken has the approval approval\n */\n function _abstractSetPToken(address _asset, address _cToken) internal {\n // Safe approval\n IERC20(_asset).safeApprove(_cToken, 0);\n IERC20(_asset).safeApprove(_cToken, uint256(-1));\n }\n\n /**\n * @dev Get the cToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding cToken to this asset\n */\n function _getCTokenFor(address _asset) internal view returns (ICERC20) {\n address cToken = assetToPToken[_asset];\n require(cToken != address(0), \"cToken does not exist\");\n return ICERC20(cToken);\n }\n\n /**\n * @dev Converts an underlying amount into cToken amount\n * cTokenAmt = (underlying * 1e18) / exchangeRate\n * @param _cToken cToken for which to change\n * @param _underlying Amount of underlying to convert\n * @return amount Equivalent amount of cTokens\n */\n function _convertUnderlyingToCToken(ICERC20 _cToken, uint256 _underlying)\n internal\n view\n returns (uint256 amount)\n {\n uint256 exchangeRate = _cToken.exchangeRateStored();\n // e.g. 1e18*1e18 / 205316390724364402565641705 = 50e8\n // e.g. 1e8*1e18 / 205316390724364402565641705 = 0.45 or 0\n amount = _underlying.mul(1e18).div(exchangeRate);\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport { ICurvePool } from \"../../strategies/ICurvePool.sol\";\nimport { StableMath } from \"../../utils/StableMath.sol\";\nimport \"../../utils/Helpers.sol\";\n\ncontract MockCurvePool is ERC20 {\n using StableMath for uint256;\n\n address[] public coins;\n address lpToken;\n\n constructor(address[3] memory _coins, address _lpToken) public {\n coins = _coins;\n lpToken = _lpToken;\n }\n\n // Returns the same amount of LP tokens in 1e18 decimals\n function add_liquidity(uint256[3] calldata _amounts, uint256 _minAmount)\n external\n {\n uint256 sum = 0;\n for (uint256 i = 0; i < _amounts.length; i++) {\n if (_amounts[i] > 0) {\n IERC20(coins[i]).transferFrom(\n msg.sender,\n address(this),\n _amounts[i]\n );\n uint256 assetDecimals = Helpers.getDecimals(coins[i]);\n // Convert to 1e18 and add to sum\n sum += _amounts[i].scaleBy(int8(18 - assetDecimals));\n }\n }\n // Hacky way of simulating slippage to check _minAmount\n if (sum == 29000e18) sum = 14500e18;\n require(sum >= _minAmount, \"Slippage ruined your day\");\n // Send LP token to sender, e.g. 3CRV\n IMintableERC20(lpToken).mint(sum);\n IERC20(lpToken).transfer(msg.sender, sum);\n }\n\n // Dumb implementation that returns the same amount\n function calc_withdraw_one_coin(uint256 _amount, int128 _index)\n public\n view\n returns (uint256)\n {\n uint256 assetDecimals = Helpers.getDecimals(coins[uint256(_index)]);\n return _amount.scaleBy(int8(assetDecimals - 18));\n }\n\n function remove_liquidity_one_coin(\n uint256 _amount,\n int128 _index,\n uint256 _minAmount\n ) external {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _amount);\n uint256[] memory amounts = new uint256[](coins.length);\n amounts[uint256(_index)] = _amount;\n uint256 amount = calc_withdraw_one_coin(_amount, _index);\n IERC20(coins[uint256(_index)]).transfer(msg.sender, amount);\n }\n\n function get_virtual_price() external returns (uint256) {\n return 1 * 10**18;\n }\n}\n" + }, + "contracts/mocks/MintableERC20.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(uint256 value) external returns (bool);\n}\n\n/**\n * @title ERC20Mintable\n * @dev ERC20 minting logic\n */\ncontract MintableERC20 is IMintableERC20, ERC20 {\n /**\n * @dev Function to mint tokens\n * @param value The amount of tokens to mint.\n * @return A boolean that indicates if the operation was successful.\n */\n function mint(uint256 value) public returns (bool) {\n _mint(msg.sender, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/MockWETH.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"WETH\";\n string public constant name = \"WETH\";\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"USDT\";\n string public constant name = \"USDT Coin\";\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"USDC\";\n string public constant name = \"USD Coin\";\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"TUSD\";\n string public constant name = \"TrueUSD\";\n}\n" + }, + "contracts/mocks/MockNonStandardToken.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\n/**\n * Mock token contract to simulate tokens that don't\n * throw/revert when a transfer/transferFrom call fails\n */\ncontract MockNonStandardToken is MintableERC20 {\n uint256 public constant decimals = 6;\n string public constant symbol = \"NonStandardToken\";\n string public constant name = \"NonStandardToken\";\n\n function transfer(address recipient, uint256 amount) public returns (bool) {\n if (balanceOf(msg.sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n if (balanceOf(sender) < amount) {\n // Fail silently\n return false;\n }\n\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n allowance(sender, _msgSender()).sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n}\n" + }, + "contracts/mocks/MockMintableUniswapPair.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"Uniswap V2\";\n string public constant name = \"UNI-V2\";\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) public MockUniswapPair(_token0, _token1, _reserve0, _reserve1) {}\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IUniswapV2Pair } from \"../interfaces/uniswap/IUniswapV2Pair.sol\";\n\ncontract MockUniswapPair is IUniswapV2Pair {\n address tok0;\n address tok1;\n uint112 reserve0;\n uint112 reserve1;\n uint256 blockTimestampLast;\n\n bool public hasSynced = false;\n\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n ) public {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view returns (address) {\n return tok0;\n }\n\n function token1() external view returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n returns (\n uint112,\n uint112,\n uint32\n )\n {\n return (reserve0, reserve1, uint32(blockTimestampLast));\n }\n\n function setReserves(uint112 _reserve0, uint112 _reserve1) public {\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n // CAUTION This will not work if you setReserves multiple times over multiple different blocks because then it wouldn't be a continuous reserve factor over that blockTimestamp,\n // this assumes an even reserve ratio all the way through\n function price0CumulativeLast() external view returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external {\n hasSynced = true;\n }\n\n function checkHasSynced() external view {\n require(hasSynced, \"Not synced\");\n }\n}\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n // range: [0, 2**112 - 1]\n // resolution: 1 / 2**112\n struct uq112x112 {\n uint224 _x;\n }\n\n // returns a uq112x112 which represents the ratio of the numerator to the denominator\n // equivalent to encode(numerator).div(denominator)\n function fraction(uint112 numerator, uint112 denominator)\n internal\n pure\n returns (uq112x112 memory)\n {\n require(denominator > 0, \"FixedPoint: DIV_BY_ZERO\");\n return uq112x112((uint224(numerator) << 112) / denominator);\n }\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Pair.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IUniswapV2Pair {\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function sync() external;\n}\n" + }, + "contracts/mocks/MockEvilDAI.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract MockEvilDAI is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"DAI\";\n string public constant name = \"DAI\";\n address host;\n address realCoin;\n\n constructor(address _host, address _realCoin) public {\n host = _host;\n realCoin = _realCoin;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _amount\n ) public returns (bool) {\n // call mint again!\n if (_amount != 69) {\n IVault(host).mint(address(this), 69, 0);\n }\n return true;\n }\n}\n" + }, + "contracts/interfaces/IVault.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IVault {\n event AssetSupported(address _asset);\n event StrategyApproved(address _addr);\n event StrategyRemoved(address _addr);\n event Mint(address _addr, uint256 _value);\n event Redeem(address _addr, uint256 _value);\n event DepositsPaused();\n event DepositsUnpaused();\n\n // Governable.sol\n function transferGovernance(address _newGovernor) external;\n\n function claimGovernance() external;\n\n function governor() external view returns (address);\n\n // VaultAdmin.sol\n function setPriceProvider(address _priceProvider) external;\n\n function priceProvider() external view returns (address);\n\n function setRedeemFeeBps(uint256 _redeemFeeBps) external;\n\n function redeemFeeBps() external view returns (uint256);\n\n function setVaultBuffer(uint256 _vaultBuffer) external;\n\n function vaultBuffer() external view returns (uint256);\n\n function setAutoAllocateThreshold(uint256 _threshold) external;\n\n function autoAllocateThreshold() external view returns (uint256);\n\n function setRebaseThreshold(uint256 _threshold) external;\n\n function rebaseThreshold() external view returns (uint256);\n\n function setStrategistAddr(address _address) external;\n\n function strategistAddr() external view returns (address);\n\n function setUniswapAddr(address _address) external;\n\n function uniswapAddr() external view returns (address);\n\n function supportAsset(address _asset) external;\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function setAssetDefaultStrategy(address _asset, address _strategy)\n external;\n\n function assetDefaultStrategies(address _asset)\n external\n view\n returns (address);\n\n function pauseRebase() external;\n\n function unpauseRebase() external;\n\n function rebasePaused() external view returns (bool);\n\n function pauseCapital() external;\n\n function unpauseCapital() external;\n\n function capitalPaused() external view returns (bool);\n\n function transferToken(address _asset, uint256 _amount) external;\n\n function harvest() external;\n\n function harvest(address _strategyAddr) external;\n\n function priceUSDMint(string calldata symbol)\n external\n view\n returns (uint256);\n\n function priceUSDRedeem(string calldata symbol)\n external\n view\n returns (uint256);\n\n // VaultCore.sol\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function mintMultiple(\n address[] calldata _assets,\n uint256[] calldata _amount,\n uint256 _minimumOusdAmount\n ) external;\n\n function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n function redeemAll(uint256 _minimumUnitAmount) external;\n\n function allocate() external;\n\n function reallocate(\n address _strategyFromAddress,\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n function rebase() external returns (uint256);\n\n function totalValue() external view returns (uint256 value);\n\n function checkBalance() external view returns (uint256);\n\n function checkBalance(address _asset) external view returns (uint256);\n\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory);\n\n function getAssetCount() external view returns (uint256);\n\n function getAllAssets() external view returns (address[] memory);\n\n function getStrategyCount() external view returns (uint256);\n\n function isSupportedAsset(address _asset) external view returns (bool);\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Vault Contract\n * @notice The Vault contract stores assets. On a deposit, OUSD will be minted\n and sent to the depositor. On a withdrawal, OUSD will be burned and\n assets will be sent to the withdrawer. The Vault accepts deposits of\n interest form yield bearing strategies which will modify the supply\n of OUSD.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract VaultCore is VaultStorage {\n uint256 constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /**\n * @dev Verifies that the rebasing is not paused.\n */\n modifier whenNotRebasePaused() {\n require(!rebasePaused, \"Rebasing paused\");\n _;\n }\n\n /**\n * @dev Verifies that the deposits are not paused.\n */\n modifier whenNotCapitalPaused() {\n require(!capitalPaused, \"Capital paused\");\n _;\n }\n\n /**\n * @dev Deposit a supported asset and mint OUSD.\n * @param _asset Address of the asset being deposited\n * @param _amount Amount of the asset being deposited\n * @param _minimumOusdAmount Minimum OUSD to mint\n */\n function mint(\n address _asset,\n uint256 _amount,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n require(assets[_asset].isSupported, \"Asset is not supported\");\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 price = IMinMaxOracle(priceProvider).priceMin(\n Helpers.getSymbol(_asset)\n );\n if (price > 1e8) {\n price = 1e8;\n }\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 unitAdjustedDeposit = _amount.scaleBy(int8(18 - assetDecimals));\n uint256 priceAdjustedDeposit = _amount.mulTruncateScale(\n price.scaleBy(int8(10)), // 18-8 because oracles have 8 decimals precision\n 10**assetDecimals\n );\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedDeposit >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedDeposit);\n\n // Rebase must happen before any transfers occur.\n if (unitAdjustedDeposit >= rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n\n // Mint matching OUSD\n oUSD.mint(msg.sender, priceAdjustedDeposit);\n\n // Transfer the deposited coins to the vault\n IERC20 asset = IERC20(_asset);\n asset.safeTransferFrom(msg.sender, address(this), _amount);\n\n if (unitAdjustedDeposit >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @dev Mint for multiple assets in the same call.\n * @param _assets Addresses of assets being deposited\n * @param _amounts Amount of each asset at the same index in the _assets\n * to deposit.\n * @param _minimumOusdAmount Minimum OUSD to mint\n */\n function mintMultiple(\n address[] calldata _assets,\n uint256[] calldata _amounts,\n uint256 _minimumOusdAmount\n ) external whenNotCapitalPaused nonReentrant {\n require(_assets.length == _amounts.length, \"Parameter length mismatch\");\n\n uint256 unitAdjustedTotal = 0;\n uint256 priceAdjustedTotal = 0;\n uint256[] memory assetPrices = _getAssetPrices(false);\n for (uint256 j = 0; j < _assets.length; j++) {\n // In memoriam\n require(assets[_assets[j]].isSupported, \"Asset is not supported\");\n require(_amounts[j] > 0, \"Amount must be greater than 0\");\n for (uint256 i = 0; i < allAssets.length; i++) {\n if (_assets[j] == allAssets[i]) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n uint256 price = assetPrices[i];\n if (price > 1e18) {\n price = 1e18;\n }\n unitAdjustedTotal = unitAdjustedTotal.add(\n _amounts[j].scaleBy(int8(18 - assetDecimals))\n );\n priceAdjustedTotal = priceAdjustedTotal.add(\n _amounts[j].mulTruncateScale(price, 10**assetDecimals)\n );\n }\n }\n }\n\n if (_minimumOusdAmount > 0) {\n require(\n priceAdjustedTotal >= _minimumOusdAmount,\n \"Mint amount lower than minimum\"\n );\n }\n\n emit Mint(msg.sender, priceAdjustedTotal);\n\n // Rebase must happen before any transfers occur.\n if (unitAdjustedTotal >= rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n\n oUSD.mint(msg.sender, priceAdjustedTotal);\n\n for (uint256 i = 0; i < _assets.length; i++) {\n IERC20 asset = IERC20(_assets[i]);\n asset.safeTransferFrom(msg.sender, address(this), _amounts[i]);\n }\n\n if (unitAdjustedTotal >= autoAllocateThreshold) {\n _allocate();\n }\n }\n\n /**\n * @dev Withdraw a supported asset and burn OUSD.\n * @param _amount Amount of OUSD to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeem(uint256 _amount, uint256 _minimumUnitAmount)\n public\n whenNotCapitalPaused\n nonReentrant\n {\n if (_amount > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n _redeem(_amount, _minimumUnitAmount);\n }\n\n /**\n * @dev Withdraw a supported asset and burn OUSD.\n * @param _amount Amount of OUSD to burn\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function _redeem(uint256 _amount, uint256 _minimumUnitAmount) internal {\n require(_amount > 0, \"Amount must be greater than 0\");\n\n uint256 _totalSupply = oUSD.totalSupply();\n uint256 _backingValue = _totalValue();\n\n if (maxSupplyDiff > 0) {\n // Allow a max difference of maxSupplyDiff% between\n // backing assets value and OUSD total supply\n uint256 diff = _totalSupply.divPrecisely(_backingValue);\n\n require(\n (diff > 1e18 ? diff.sub(1e18) : uint256(1e18).sub(diff)) <=\n maxSupplyDiff,\n \"Backing supply liquidity error\"\n );\n }\n\n emit Redeem(msg.sender, _amount);\n\n // Calculate redemption outputs\n uint256[] memory outputs = _calculateRedeemOutputs(_amount);\n // Send outputs\n for (uint256 i = 0; i < allAssets.length; i++) {\n if (outputs[i] == 0) continue;\n\n IERC20 asset = IERC20(allAssets[i]);\n\n if (asset.balanceOf(address(this)) >= outputs[i]) {\n // Use Vault funds first if sufficient\n asset.safeTransfer(msg.sender, outputs[i]);\n } else {\n address strategyAddr = assetDefaultStrategies[allAssets[i]];\n if (strategyAddr != address(0)) {\n // Nothing in Vault, but something in Strategy, send from there\n IStrategy strategy = IStrategy(strategyAddr);\n strategy.withdraw(msg.sender, allAssets[i], outputs[i]);\n } else {\n // Cant find funds anywhere\n revert(\"Liquidity error\");\n }\n }\n }\n\n if (_minimumUnitAmount > 0) {\n uint256 unitTotal = 0;\n for (uint256 i = 0; i < outputs.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n unitTotal = unitTotal.add(\n outputs[i].scaleBy(int8(18 - assetDecimals))\n );\n }\n require(\n unitTotal >= _minimumUnitAmount,\n \"Redeem amount lower than minimum\"\n );\n }\n\n oUSD.burn(msg.sender, _amount);\n\n // Until we can prove that we won't affect the prices of our assets\n // by withdrawing them, this should be here.\n // It's possible that a strategy was off on its asset total, perhaps\n // a reward token sold for more or for less than anticipated.\n if (_amount > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n }\n\n /**\n * @notice Withdraw a supported asset and burn all OUSD.\n * @param _minimumUnitAmount Minimum stablecoin units to receive in return\n */\n function redeemAll(uint256 _minimumUnitAmount)\n external\n whenNotCapitalPaused\n nonReentrant\n {\n // Unfortunately we have to do balanceOf twice, the rebase may change\n // the account balance\n if (oUSD.balanceOf(msg.sender) > rebaseThreshold && !rebasePaused) {\n _rebase();\n }\n _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount);\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function allocate() public whenNotCapitalPaused nonReentrant {\n _allocate();\n }\n\n /**\n * @notice Allocate unallocated funds on Vault to strategies.\n * @dev Allocate unallocated funds on Vault to strategies.\n **/\n function _allocate() internal {\n uint256 vaultValue = _totalValueInVault();\n // Nothing in vault to allocate\n if (vaultValue == 0) return;\n uint256 strategiesValue = _totalValueInStrategies();\n // We have a method that does the same as this, gas optimisation\n uint256 calculatedTotalValue = vaultValue.add(strategiesValue);\n\n // We want to maintain a buffer on the Vault so calculate a percentage\n // modifier to multiply each amount being allocated by to enforce the\n // vault buffer\n uint256 vaultBufferModifier;\n if (strategiesValue == 0) {\n // Nothing in Strategies, allocate 100% minus the vault buffer to\n // strategies\n vaultBufferModifier = uint256(1e18).sub(vaultBuffer);\n } else {\n vaultBufferModifier = vaultBuffer.mul(calculatedTotalValue).div(\n vaultValue\n );\n if (1e18 > vaultBufferModifier) {\n // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17\n // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault\n vaultBufferModifier = uint256(1e18).sub(vaultBufferModifier);\n } else {\n // We need to let the buffer fill\n return;\n }\n }\n if (vaultBufferModifier == 0) return;\n\n // Iterate over all assets in the Vault and allocate the the appropriate\n // strategy\n for (uint256 i = 0; i < allAssets.length; i++) {\n IERC20 asset = IERC20(allAssets[i]);\n uint256 assetBalance = asset.balanceOf(address(this));\n // No balance, nothing to do here\n if (assetBalance == 0) continue;\n\n // Multiply the balance by the vault buffer modifier and truncate\n // to the scale of the asset decimals\n uint256 allocateAmount = assetBalance.mulTruncate(\n vaultBufferModifier\n );\n\n address depositStrategyAddr = assetDefaultStrategies[address(\n asset\n )];\n\n if (depositStrategyAddr != address(0) && allocateAmount > 0) {\n IStrategy strategy = IStrategy(depositStrategyAddr);\n // Transfer asset to Strategy and call deposit method to\n // mint or take required action\n asset.safeTransfer(address(strategy), allocateAmount);\n strategy.deposit(address(asset), allocateAmount);\n }\n }\n\n // Harvest for all reward tokens above reward liquidation threshold\n for (uint256 i = 0; i < allStrategies.length; i++) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n address rewardTokenAddress = strategy.rewardTokenAddress();\n if (rewardTokenAddress != address(0)) {\n uint256 liquidationThreshold = strategy\n .rewardLiquidationThreshold();\n if (liquidationThreshold == 0) {\n // No threshold set, always harvest from strategy\n IVault(address(this)).harvest(allStrategies[i]);\n } else {\n // Check balance against liquidation threshold\n // Note some strategies don't hold the reward token balance\n // on their contract so the liquidation threshold should be\n // set to 0\n IERC20 rewardToken = IERC20(rewardTokenAddress);\n uint256 rewardTokenAmount = rewardToken.balanceOf(\n allStrategies[i]\n );\n if (rewardTokenAmount >= liquidationThreshold) {\n IVault(address(this)).harvest(allStrategies[i]);\n }\n }\n }\n }\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OUSD.\n * @return uint256 New total supply of OUSD\n */\n function rebase()\n public\n whenNotRebasePaused\n nonReentrant\n returns (uint256 newTotalSupply)\n {\n return _rebase();\n }\n\n /**\n * @dev Calculate the total value of assets held by the Vault and all\n * strategies and update the supply of OUSD.\n * @return uint256 New total supply of OUSD\n */\n function _rebase()\n internal\n whenNotRebasePaused\n returns (uint256 newTotalSupply)\n {\n if (oUSD.totalSupply() == 0) return 0;\n uint256 oldTotalSupply = oUSD.totalSupply();\n newTotalSupply = _totalValue();\n // Only rachet upwards\n if (newTotalSupply > oldTotalSupply) {\n oUSD.changeSupply(newTotalSupply);\n }\n }\n\n /**\n * @dev Determine the total value of assets held by the vault and its\n * strategies.\n * @return uint256 value Total value in USD (1e18)\n */\n function totalValue() external view returns (uint256 value) {\n value = _totalValue();\n }\n\n /**\n * @dev Internal Calculate the total value of the assets held by the\n * vault and its strategies.\n * @return uint256 value Total value in USD (1e18)\n */\n function _totalValue() internal view returns (uint256 value) {\n return _totalValueInVault().add(_totalValueInStrategies());\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Vault.\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInVault() internal view returns (uint256 value) {\n for (uint256 y = 0; y < allAssets.length; y++) {\n IERC20 asset = IERC20(allAssets[y]);\n uint256 assetDecimals = Helpers.getDecimals(allAssets[y]);\n uint256 balance = asset.balanceOf(address(this));\n if (balance > 0) {\n value = value.add(balance.scaleBy(int8(18 - assetDecimals)));\n }\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Strategies.\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInStrategies() internal view returns (uint256 value) {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n value = value.add(_totalValueInStrategy(allStrategies[i]));\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held by strategy.\n * @param _strategyAddr Address of the strategy\n * @return uint256 Total value in ETH (1e18)\n */\n function _totalValueInStrategy(address _strategyAddr)\n internal\n view\n returns (uint256 value)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n for (uint256 y = 0; y < allAssets.length; y++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[y]);\n if (strategy.supportsAsset(allAssets[y])) {\n uint256 balance = strategy.checkBalance(allAssets[y]);\n if (balance > 0) {\n value = value.add(\n balance.scaleBy(int8(18 - assetDecimals))\n );\n }\n }\n }\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function checkBalance(address _asset) external view returns (uint256) {\n return _checkBalance(_asset);\n }\n\n /**\n * @notice Get the balance of an asset held in Vault and all strategies.\n * @param _asset Address of asset\n * @return uint256 Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n returns (uint256 balance)\n {\n IERC20 asset = IERC20(_asset);\n balance = asset.balanceOf(address(this));\n for (uint256 i = 0; i < allStrategies.length; i++) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n if (strategy.supportsAsset(_asset)) {\n balance = balance.add(strategy.checkBalance(_asset));\n }\n }\n }\n\n /**\n * @notice Get the balance of all assets held in Vault and all strategies.\n * @return uint256 Balance of all assets (1e18)\n */\n function _checkBalance() internal view returns (uint256 balance) {\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 assetDecimals = Helpers.getDecimals(allAssets[i]);\n balance = balance.add(\n _checkBalance(allAssets[i]).scaleBy(int8(18 - assetDecimals))\n );\n }\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned\n */\n function calculateRedeemOutputs(uint256 _amount)\n external\n view\n returns (uint256[] memory)\n {\n return _calculateRedeemOutputs(_amount);\n }\n\n /**\n * @notice Calculate the outputs for a redeem function, i.e. the mix of\n * coins that will be returned.\n * @return Array of amounts respective to the supported assets\n */\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n returns (uint256[] memory outputs)\n {\n // We always give out coins in proportion to how many we have,\n // Now if all coins were the same value, this math would easy,\n // just take the percentage of each coin, and multiply by the\n // value to be given out. But if coins are worth more than $1,\n // then we would end up handing out too many coins. We need to\n // adjust by the total value of coins.\n //\n // To do this, we total up the value of our coins, by their\n // percentages. Then divide what we would otherwise give out by\n // this number.\n //\n // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00.\n // So for every 1 DAI we give out, we'll be handing out 2 USDT\n // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02\n //\n // So when calculating the output, we take the percentage of\n // each coin, times the desired output value, divided by the\n // totalOutputRatio.\n //\n // For example, withdrawing: 30 OUSD:\n // DAI 33% * 30 / 1.02 = 9.80 DAI\n // USDT = 66 % * 30 / 1.02 = 19.60 USDT\n //\n // Checking these numbers:\n // 9.80 DAI * 1.06 = $10.40\n // 19.60 USDT * 1.00 = $19.60\n //\n // And so the user gets $10.40 + $19.60 = $30 worth of value.\n\n uint256 assetCount = getAssetCount();\n uint256[] memory assetPrices = _getAssetPrices(true);\n uint256[] memory assetBalances = new uint256[](assetCount);\n uint256[] memory assetDecimals = new uint256[](assetCount);\n uint256 totalBalance = 0;\n uint256 totalOutputRatio = 0;\n outputs = new uint256[](assetCount);\n\n // Calculate redeem fee\n if (redeemFeeBps > 0) {\n uint256 redeemFee = _amount.mul(redeemFeeBps).div(10000);\n _amount = _amount.sub(redeemFee);\n }\n\n // Calculate assets balances and decimals once,\n // for a large gas savings.\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 balance = _checkBalance(allAssets[i]);\n uint256 decimals = Helpers.getDecimals(allAssets[i]);\n assetBalances[i] = balance;\n assetDecimals[i] = decimals;\n totalBalance = totalBalance.add(\n balance.scaleBy(int8(18 - decimals))\n );\n }\n // Calculate totalOutputRatio\n for (uint256 i = 0; i < allAssets.length; i++) {\n uint256 price = assetPrices[i];\n // Never give out more than one\n // stablecoin per dollar of OUSD\n if (price < 1e18) {\n price = 1e18;\n }\n uint256 ratio = assetBalances[i]\n .scaleBy(int8(18 - assetDecimals[i]))\n .mul(price)\n .div(totalBalance);\n totalOutputRatio = totalOutputRatio.add(ratio);\n }\n // Calculate final outputs\n uint256 factor = _amount.divPrecisely(totalOutputRatio);\n for (uint256 i = 0; i < allAssets.length; i++) {\n outputs[i] = assetBalances[i].mul(factor).div(totalBalance);\n }\n }\n\n /**\n * @notice Get an array of the supported asset prices in USD.\n * @return uint256[] Array of asset prices in USD (1e18)\n */\n function _getAssetPrices(bool useMax)\n internal\n view\n returns (uint256[] memory assetPrices)\n {\n assetPrices = new uint256[](getAssetCount());\n\n IMinMaxOracle oracle = IMinMaxOracle(priceProvider);\n // Price from Oracle is returned with 8 decimals\n // _amount is in assetDecimals\n\n for (uint256 i = 0; i < allAssets.length; i++) {\n string memory symbol = Helpers.getSymbol(allAssets[i]);\n // Get all the USD prices of the asset in 1e18\n if (useMax) {\n assetPrices[i] = oracle.priceMax(symbol).scaleBy(int8(18 - 8));\n } else {\n assetPrices[i] = oracle.priceMin(symbol).scaleBy(int8(18 - 8));\n }\n }\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @dev Return the number of assets suppported by the Vault.\n */\n function getAssetCount() public view returns (uint256) {\n return allAssets.length;\n }\n\n /**\n * @dev Return all asset addresses in order\n */\n function getAllAssets() external view returns (address[] memory) {\n return allAssets;\n }\n\n /**\n * @dev Return the number of strategies active on the Vault.\n */\n function getStrategyCount() external view returns (uint256) {\n return allStrategies.length;\n }\n\n function isSupportedAsset(address _asset) external view returns (bool) {\n return assets[_asset].isSupported;\n }\n\n /**\n * @dev Falldown to the admin implementation\n * @notice This is a catch all for all functions not declared in core\n */\n function() external payable {\n bytes32 slot = adminImplPosition;\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize)\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas, sload(slot), 0, calldatasize, 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize)\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize)\n }\n default {\n return(0, returndatasize)\n }\n }\n }\n}\n" + }, + "contracts/oracle/MixOracle.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD MixOracle Contract\n * @notice The MixOracle pulls exchange rate from multiple oracles and returns\n * min and max values.\n * @author Origin Protocol Inc\n */\nimport { IPriceOracle } from \"../interfaces/IPriceOracle.sol\";\nimport { IEthUsdOracle } from \"../interfaces/IEthUsdOracle.sol\";\nimport { IMinMaxOracle } from \"../interfaces/IMinMaxOracle.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract MixOracle is IMinMaxOracle, Governable {\n event DriftsUpdated(uint256 _minDrift, uint256 _maxDrift);\n event EthUsdOracleRegistered(address _oracle);\n event EthUsdOracleDeregistered(address _oracle);\n event TokenOracleRegistered(\n string symbol,\n address[] ethOracles,\n address[] usdOracles\n );\n\n address[] public ethUsdOracles;\n\n struct MixConfig {\n address[] usdOracles;\n address[] ethOracles;\n }\n\n mapping(bytes32 => MixConfig) configs;\n\n uint256 constant MAX_INT = 2**256 - 1;\n uint256 public maxDrift;\n uint256 public minDrift;\n\n constructor(uint256 _maxDrift, uint256 _minDrift) public {\n maxDrift = _maxDrift;\n minDrift = _minDrift;\n emit DriftsUpdated(_minDrift, _maxDrift);\n }\n\n function setMinMaxDrift(uint256 _minDrift, uint256 _maxDrift)\n public\n onlyGovernor\n {\n minDrift = _minDrift;\n maxDrift = _maxDrift;\n emit DriftsUpdated(_minDrift, _maxDrift);\n }\n\n /**\n * @notice Adds an oracle to the list of oracles to pull data from.\n * @param oracle Address of an oracle that implements the IEthUsdOracle interface.\n **/\n function registerEthUsdOracle(address oracle) public onlyGovernor {\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n require(ethUsdOracles[i] != oracle, \"Oracle already registered.\");\n }\n ethUsdOracles.push(oracle);\n emit EthUsdOracleRegistered(oracle);\n }\n\n /**\n * @notice Removes an oracle to the list of oracles to pull data from.\n * @param oracle Address of an oracle that implements the IEthUsdOracle interface.\n **/\n function unregisterEthUsdOracle(address oracle) public onlyGovernor {\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n if (ethUsdOracles[i] == oracle) {\n // swap with the last element of the array, and then delete last element (could be itself)\n ethUsdOracles[i] = ethUsdOracles[ethUsdOracles.length - 1];\n delete ethUsdOracles[ethUsdOracles.length - 1];\n emit EthUsdOracleDeregistered(oracle);\n ethUsdOracles.pop();\n return;\n }\n }\n revert(\"Oracle not found\");\n }\n\n /**\n * @notice Adds an oracle to the list of oracles to pull data from.\n * @param ethOracles Addresses of oracles that implements the IEthUsdOracle interface and answers for this asset\n * @param usdOracles Addresses of oracles that implements the IPriceOracle interface and answers for this asset\n **/\n function registerTokenOracles(\n string calldata symbol,\n address[] calldata ethOracles,\n address[] calldata usdOracles\n ) external onlyGovernor {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n config.ethOracles = ethOracles;\n config.usdOracles = usdOracles;\n emit TokenOracleRegistered(symbol, ethOracles, usdOracles);\n }\n\n /**\n * @notice Returns the min price of an asset in USD.\n * @return symbol Asset symbol. Example: \"DAI\"\n * @return price Min price from all the oracles, in USD with 8 decimal digits.\n **/\n function priceMin(string calldata symbol)\n external\n view\n returns (uint256 price)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n uint256 ep;\n uint256 p; //holder variables\n price = MAX_INT;\n if (config.ethOracles.length > 0) {\n ep = MAX_INT;\n for (uint256 i = 0; i < config.ethOracles.length; i++) {\n p = IEthUsdOracle(config.ethOracles[i]).tokEthPrice(symbol);\n if (ep > p) {\n ep = p;\n }\n }\n price = ep;\n ep = MAX_INT;\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n p = IEthUsdOracle(ethUsdOracles[i]).ethUsdPrice();\n if (ep > p) {\n ep = p;\n }\n }\n if (price != MAX_INT && ep != MAX_INT) {\n // tokEthPrice has precision of 8 which ethUsdPrice has precision of 6\n // we want precision of 8\n price = (price * ep) / 1e6;\n }\n }\n\n if (config.usdOracles.length > 0) {\n for (uint256 i = 0; i < config.usdOracles.length; i++) {\n // upscale by 2 since price oracles are precision 6\n p = IPriceOracle(config.usdOracles[i]).price(symbol) * 1e2;\n if (price > p) {\n price = p;\n }\n }\n }\n require(price <= maxDrift, \"Price exceeds maxDrift\");\n require(price >= minDrift, \"Price below minDrift\");\n require(\n price != MAX_INT,\n \"None of our oracles returned a valid min price!\"\n );\n }\n\n /**\n * @notice Returns max price of an asset in USD.\n * @return symbol Asset symbol. Example: \"DAI\"\n * @return price Max price from all the oracles, in USD with 8 decimal digits.\n **/\n function priceMax(string calldata symbol)\n external\n view\n returns (uint256 price)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n uint256 ep;\n uint256 p; //holder variables\n price = 0;\n if (config.ethOracles.length > 0) {\n ep = 0;\n for (uint256 i = 0; i < config.ethOracles.length; i++) {\n p = IEthUsdOracle(config.ethOracles[i]).tokEthPrice(symbol);\n if (ep < p) {\n ep = p;\n }\n }\n price = ep;\n ep = 0;\n for (uint256 i = 0; i < ethUsdOracles.length; i++) {\n p = IEthUsdOracle(ethUsdOracles[i]).ethUsdPrice();\n if (ep < p) {\n ep = p;\n }\n }\n if (price != 0 && ep != 0) {\n // tokEthPrice has precision of 8 which ethUsdPrice has precision of 6\n // we want precision of 8\n price = (price * ep) / 1e6;\n }\n }\n\n if (config.usdOracles.length > 0) {\n for (uint256 i = 0; i < config.usdOracles.length; i++) {\n // upscale by 2 since price oracles are precision 6\n p = IPriceOracle(config.usdOracles[i]).price(symbol) * 1e2;\n if (price < p) {\n price = p;\n }\n }\n }\n\n require(price <= maxDrift, \"Price exceeds maxDrift\");\n require(price >= minDrift, \"Price below minDrift\");\n require(price != 0, \"None of our oracles returned a valid max price!\");\n }\n\n /**\n * @notice Returns the length of the usdOracles array for a given token\n * @param symbol Asset symbol. Example: \"DAI\"\n * @return length of the USD oracles array\n **/\n function getTokenUSDOraclesLength(string calldata symbol)\n external\n view\n returns (uint256)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.usdOracles.length;\n }\n\n /**\n * @notice Returns the address of a specific USD oracle\n * @param symbol Asset symbol. Example: \"DAI\"\n * @param idx Index of the array value to return\n * @return address of the oracle\n **/\n function getTokenUSDOracle(string calldata symbol, uint256 idx)\n external\n view\n returns (address)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.usdOracles[idx];\n }\n\n /**\n * @notice Returns the length of the ethOracles array for a given token\n * @param symbol Asset symbol. Example: \"DAI\"\n * @return length of the ETH oracles array\n **/\n function getTokenETHOraclesLength(string calldata symbol)\n external\n view\n returns (uint256)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.ethOracles.length;\n }\n\n /**\n * @notice Returns the address of a specific ETH oracle\n * @param symbol Asset symbol. Example: \"DAI\"\n * @param idx Index of the array value to return\n * @return address of the oracle\n **/\n function getTokenETHOracle(string calldata symbol, uint256 idx)\n external\n view\n returns (address)\n {\n MixConfig storage config = configs[keccak256(abi.encodePacked(symbol))];\n return config.ethOracles[idx];\n }\n}\n" + }, + "contracts/interfaces/IPriceOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IPriceOracle {\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IEthUsdOracle.sol": { + "content": "pragma solidity 0.5.11;\n\ninterface IEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n\ninterface IViewEthUsdOracle {\n /**\n * @notice Returns ETH price in USD.\n * @return Price in USD with 6 decimal digits.\n */\n function ethUsdPrice() external view returns (uint256);\n\n /**\n * @notice Returns token price in USD.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in USD with 6 decimal digits.\n */\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the asset price in ETH.\n * @param symbol. Asset symbol. For ex. \"DAI\".\n * @return Price in ETH with 8 decimal digits.\n */\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/oracle/ChainlinkOracle.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD ChainlinkOracle Contract\n * @author Origin Protocol Inc\n */\nimport \"./AggregatorV3Interface.sol\";\nimport { IPriceOracle } from \"../interfaces/IPriceOracle.sol\";\nimport { IEthUsdOracle } from \"../interfaces/IEthUsdOracle.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\ncontract ChainlinkOracle is IEthUsdOracle, IPriceOracle, Governable {\n event FeedRegistered(address _feed, string _symbol, bool _directToUsd);\n\n address ethFeed;\n\n struct FeedConfig {\n address feed;\n uint8 decimals;\n bool directToUsd;\n }\n\n mapping(bytes32 => FeedConfig) feeds;\n\n uint8 ethDecimals;\n\n string constant ethSymbol = \"ETH\";\n bytes32 constant ethHash = keccak256(abi.encodePacked(ethSymbol));\n\n constructor(address ethFeed_) public {\n ethFeed = ethFeed_;\n ethDecimals = AggregatorV3Interface(ethFeed_).decimals();\n }\n\n function registerFeed(\n address feed,\n string memory symbol,\n bool directToUsd\n ) public onlyGovernor {\n FeedConfig storage config = feeds[keccak256(abi.encodePacked(symbol))];\n\n config.feed = feed;\n config.decimals = AggregatorV3Interface(feed).decimals();\n config.directToUsd = directToUsd;\n\n emit FeedRegistered(feed, symbol, directToUsd);\n }\n\n function getLatestPrice(address feed) internal view returns (int256) {\n (\n uint80 roundID,\n int256 price,\n uint256 startedAt,\n uint256 timeStamp,\n uint80 answeredInRound\n ) = AggregatorV3Interface(feed).latestRoundData();\n // silence\n roundID;\n startedAt;\n timeStamp;\n answeredInRound;\n return price;\n }\n\n function ethUsdPrice() external view returns (uint256) {\n return (uint256(getLatestPrice(ethFeed)) /\n (uint256(10)**(ethDecimals - 6)));\n }\n\n function tokUsdPrice(string calldata symbol)\n external\n view\n returns (uint256)\n {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n require(config.directToUsd, \"Price is not direct to usd\");\n require(tPrice > 0, \"Price must be greater than zero\");\n return uint256(tPrice);\n }\n\n function tokEthPrice(string calldata symbol)\n external\n view\n returns (uint256)\n {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n require(!config.directToUsd, \"Price is not in terms of ETH\");\n require(tPrice > 0, \"Price must be greater than zero\");\n //attempt to return 8 digit precision here\n return uint256(tPrice) / (uint256(10)**(config.decimals - 8));\n }\n\n // This actually calculate the latest price from outside oracles\n // It's a view but substantially more costly in terms of calculation\n function price(string calldata symbol) external view returns (uint256) {\n bytes32 tokenSymbolHash = keccak256(abi.encodePacked(symbol));\n\n if (ethHash == tokenSymbolHash) {\n return (uint256(getLatestPrice(ethFeed)) /\n (uint256(10)**(ethDecimals - 6)));\n } else {\n FeedConfig storage config = feeds[tokenSymbolHash];\n int256 tPrice = getLatestPrice(config.feed);\n\n if (config.directToUsd) {\n require(tPrice > 0, \"Price must be greater than zero\");\n return uint256(tPrice);\n } else {\n int256 ethPrice = getLatestPrice(ethFeed); // grab the eth price from the open oracle\n require(\n tPrice > 0 && ethPrice > 0,\n \"Both eth and price must be greater than zero\"\n );\n //not actually sure why it's 6 units here, this is just to match with openoracle for now\n return\n mul(uint256(tPrice), uint256(ethPrice)) /\n (uint256(10)**(ethDecimals + config.decimals - 6));\n }\n }\n }\n\n /// @dev Overflow proof multiplication\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a == 0) return 0;\n uint256 c = a * b;\n require(c / a == b, \"multiplication overflow\");\n return c;\n }\n}\n" + }, + "contracts/oracle/AggregatorV3Interface.sol": { + "content": "pragma solidity ^0.5.11;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "contracts/mocks/MockOracle.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../interfaces/IPriceOracle.sol\";\nimport \"../interfaces/IMinMaxOracle.sol\";\n\n/**\n * Mock of both price Oracle and min max oracles\n */\ncontract MockOracle is IPriceOracle, IMinMaxOracle {\n mapping(bytes32 => uint256) prices;\n mapping(bytes32 => uint256[]) pricesMinMax;\n uint256 ethMin;\n uint256 ethMax;\n\n /**\n * @dev returns the asset price in USD, 6 decimal digits.\n * Compatible with the Open Price Feed.\n */\n function price(string calldata symbol) external view returns (uint256) {\n return prices[keccak256(abi.encodePacked(symbol))];\n }\n\n /**\n * @dev sets the price of the asset in USD, 6 decimal digits\n *\n */\n function setPrice(string calldata symbol, uint256 _price) external {\n prices[keccak256(abi.encodePacked(symbol))] = _price;\n }\n\n /**\n * @dev sets the min and max price of ETH in USD, 6 decimal digits\n *\n */\n function setEthPriceMinMax(uint256 _min, uint256 _max) external {\n ethMin = _min;\n ethMax = _max;\n }\n\n /**\n * @dev sets the prices Min Max for a specific symbol in ETH, 8 decimal digits\n *\n */\n function setTokPriceMinMax(\n string calldata symbol,\n uint256 _min,\n uint256 _max\n ) external {\n pricesMinMax[keccak256(abi.encodePacked(symbol))] = [_min, _max];\n }\n\n /**\n * @dev get the price of asset in ETH, 8 decimal digits.\n */\n function priceMin(string calldata symbol) external view returns (uint256) {\n uint256[] storage pMinMax = pricesMinMax[keccak256(\n abi.encodePacked(symbol)\n )];\n return (pMinMax[0] * ethMin) / 1e6;\n }\n\n /**\n * @dev get the price of asset in USD, 8 decimal digits.\n * Not needed for now\n */\n function priceMax(string calldata symbol) external view returns (uint256) {\n uint256[] storage pMinMax = pricesMinMax[keccak256(\n abi.encodePacked(symbol)\n )];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockChainlinkOracleFeed.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../oracle/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) public {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view returns (uint8) {\n return numDecimals;\n }\n\n function description() external view returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external view returns (uint256) {\n return 1;\n }\n\n function setPrice(int256 _price) public {\n price = _price;\n }\n\n function setDecimals(uint8 _decimals) public {\n numDecimals = _decimals;\n }\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = _roundId;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n roundId = 0;\n answer = price;\n startedAt = 0;\n updatedAt = 0;\n answeredInRound = 0;\n }\n}\n" + }, + "contracts/mocks/MockVault.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\nimport { VaultInitializer } from \"../vault/VaultInitializer.sol\";\n\ncontract MockVault is VaultCore, VaultInitializer {\n uint256 storedTotalValue;\n\n function setTotalValue(uint256 _totalValue) public {\n storedTotalValue = _totalValue;\n }\n\n function totalValue() external view returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view returns (uint256) {\n return storedTotalValue;\n }\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n }\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The Vault contract initializes the vault.\n * @author Origin Protocol Inc\n */\n\nimport \"./VaultStorage.sol\";\n\ncontract VaultInitializer is VaultStorage {\n function initialize(address _priceProvider, address _ousd)\n external\n onlyGovernor\n initializer\n {\n require(_priceProvider != address(0), \"PriceProvider address is zero\");\n require(_ousd != address(0), \"oUSD address is zero\");\n\n oUSD = OUSD(_ousd);\n\n priceProvider = _priceProvider;\n\n rebasePaused = false;\n capitalPaused = true;\n\n // Initial redeem fee of 0 basis points\n redeemFeeBps = 0;\n // Initial Vault buffer of 0%\n vaultBuffer = 0;\n // Initial allocate threshold of 25,000 OUSD\n autoAllocateThreshold = 25000e18;\n // Threshold for rebasing\n rebaseThreshold = 1000e18;\n }\n}\n" + }, + "contracts/vault/Vault.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD VaultInitializer Contract\n * @notice The VaultInitializer sets up the initial contract.\n * @author Origin Protocol Inc\n */\nimport { VaultInitializer } from \"./VaultInitializer.sol\";\nimport { VaultAdmin } from \"./VaultAdmin.sol\";\n\ncontract Vault is VaultInitializer, VaultAdmin {}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nimport { OUSD } from \"../token/OUSD.sol\";\n\ncontract MockNonRebasing {\n OUSD oUSD;\n\n function setOUSD(address _oUSDAddress) public {\n oUSD = OUSD(_oUSDAddress);\n }\n\n function rebaseOptIn() public {\n oUSD.rebaseOptIn();\n }\n\n function rebaseOptOut() public {\n oUSD.rebaseOptOut();\n }\n\n function transfer(address _to, uint256 _value) public {\n oUSD.transfer(_to, _value);\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public {\n oUSD.transferFrom(_from, _to, _value);\n }\n\n function increaseAllowance(address _spender, uint256 _addedValue) public {\n oUSD.increaseAllowance(_spender, _addedValue);\n }\n\n function mintOusd(\n address _vaultContract,\n address _asset,\n uint256 _amount\n ) public {\n IVault(_vaultContract).mint(_asset, _amount, 0);\n }\n\n function redeemOusd(address _vaultContract, uint256 _amount) public {\n IVault(_vaultContract).redeem(_amount, 0);\n }\n\n function approveFor(\n address _contract,\n address _spender,\n uint256 _addedValue\n ) public {\n IERC20(_contract).approve(_spender, _addedValue);\n }\n}\n" + }, + "contracts/token/OUSDReset.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { OUSD } from \"./OUSD.sol\";\n\ncontract OUSDReset is OUSD {\n /**\n * Reset function to restore initial state.\n * TODO Remove\n */\n function reset() external onlyGovernor {\n _name = \"Origin Dollar\";\n _symbol = \"OUSD\";\n _decimals = 18;\n rebasingCreditsPerToken = 1e18;\n }\n\n function setVaultAddress(address _vaultAddress) external onlyGovernor {\n vaultAddress = _vaultAddress;\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\n\ncontract MockCRVMinter {\n address crv;\n\n constructor(address _crv) public {\n crv = _crv;\n }\n\n function mint(address _address) external {\n uint256 amount = 2e18;\n IMintableERC20(crv).mint(amount);\n IERC20(crv).transfer(_address, amount);\n }\n}\n" + }, + "contracts/liquidity/LiquidityReward.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/SafeERC20.sol\";\n\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\n//\n// LiquidityReward contract doles out reward for liquidity\n// base off of Sushiswap's MasterChef: https://github.com/sushiswap/sushiswap/blob/master/contracts/MasterChef.sol\n//\ncontract LiquidityReward is Initializable, Governable {\n using SafeMath for uint256;\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n int256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of Reward Tokens\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n //\n // NOTE: rewardDebt can go negative because we allow withdraws without claiming the reward\n // in that case we owe the account holder some reward.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 lastRewardBlock; // Last block number that Reward calculation occurs.\n uint256 accRewardPerShare; // Accumulated Reward per share in reward precision. See below.\n }\n\n // The Reward token\n IERC20 public reward;\n\n // Reward tokens created per block in 1e18 precision.\n uint256 public rewardPerBlock;\n\n // Info on the LP.\n PoolInfo public pool;\n // total Reward debt, useful to calculate if we have enough to pay out all rewards\n int256 public totalRewardDebt;\n // Info of each user that stakes LP tokens.\n mapping(address => UserInfo) public userInfo;\n // The block number when Liquidity rewards ends.\n uint256 public endBlock;\n\n event CampaignStarted(\n uint256 rewardRate,\n uint256 startBlock,\n uint256 endBlock\n );\n event CampaignStopped(uint256 endBlock);\n event Deposit(address indexed user, uint256 amount);\n event Withdraw(address indexed user, uint256 amount);\n event Claim(address indexed user, uint256 amount);\n\n /**\n * Initializer for setting up Liquidity Reward internal state.\n * @param _reward Address of the reward token(OGN)\n * @param _lpToken Address of the LP token(Uniswap Pair)\n */\n function initialize(IERC20 _reward, IERC20 _lpToken)\n external\n onlyGovernor\n initializer\n {\n reward = _reward;\n pool.lpToken = _lpToken;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev start a new reward campaign.\n * This will calculate all rewards up to the current block at the old rate.\n * This ensures that we pay everyone at the promised rate before update to the new rate.\n * @param _rewardPerBlock Amount rewarded per block\n * @param _startBlock Block number that we want to start the rewards at (0 for current block)\n * @param _numBlocks number of blocks that the campaign should last\n */\n function startCampaign(\n uint256 _rewardPerBlock,\n uint256 _startBlock,\n uint256 _numBlocks\n ) external onlyGovernor {\n // Calculate up to the current block at the current rate for everyone.\n updatePool();\n\n // total Pending calculated at the current pool rate\n uint256 totalPending = subDebt(\n pool.accRewardPerShare.mulTruncate(\n pool.lpToken.balanceOf(address(this))\n ),\n totalRewardDebt\n );\n\n require(\n reward.balanceOf(address(this)) >=\n _rewardPerBlock.mul(_numBlocks).add(totalPending),\n \"startCampaign: insufficient rewards\"\n );\n\n uint256 startBlock = _startBlock;\n if (startBlock == 0) {\n // start block number isn't given so we start at the current\n startBlock = block.number;\n }\n require(\n startBlock >= block.number,\n \"startCampaign: _startBlock can't be in the past\"\n );\n endBlock = startBlock.add(_numBlocks);\n // we don't start accrue until the startBlock\n pool.lastRewardBlock = startBlock;\n // new blocks start at the new reward rate\n rewardPerBlock = _rewardPerBlock;\n emit CampaignStarted(rewardPerBlock, startBlock, endBlock);\n }\n\n function stopCampaign() external onlyGovernor {\n //calculate until current pool\n updatePool();\n //end the block here (the CampaignMultiplier will be zero)\n endBlock = block.number;\n emit CampaignStopped(endBlock);\n }\n\n function campaignActive() external view returns (bool) {\n return endBlock > block.number && block.number >= pool.lastRewardBlock;\n }\n\n function balanceOf(address _account) external view returns (uint256) {\n return userInfo[_account].amount;\n }\n\n /**\n * @dev calculate the number of blocks since we last updated\n * within start and end as constraints\n * @param _to Block number of the ending point.\n * @return multiplier Multiplier over the given _from to _to block.\n */\n function getCampaignMultiplier(uint256 _to)\n internal\n view\n returns (uint256)\n {\n uint256 from = pool.lastRewardBlock;\n if (from > endBlock) {\n return 0;\n } else {\n return (_to < endBlock ? _to : endBlock).sub(from);\n }\n }\n\n /**\n * @dev View function to see pending rewards for each account on frontend.\n * @param _user Address of the account we're looking up.\n * @return reward Total rewards owed to this account.\n */\n function pendingRewards(address _user) external view returns (uint256) {\n UserInfo storage user = userInfo[_user];\n return _pendingRewards(user);\n }\n\n function _pendingRewards(UserInfo storage user)\n internal\n view\n returns (uint256)\n {\n uint256 accRewardPerShare = pool.accRewardPerShare;\n if (block.number > pool.lastRewardBlock) {\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (lpSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n }\n }\n return\n subDebt(\n user.amount.mulTruncate(accRewardPerShare),\n user.rewardDebt\n );\n }\n\n /**\n * @dev View function to see total outstanding rewards for the entire contract.\n * This is how much is owed when everyone pulls out.\n * @return reward Total rewards owed to everyone.\n */\n function totalOutstandingRewards() external view returns (uint256) {\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && lpSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n uint256 accRewardPerShare = pool.accRewardPerShare;\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(lpSupply),\n totalRewardDebt\n );\n }\n // no supply or not even started\n return 0;\n }\n\n /**\n * @dev External call for updating the pool.\n */\n function doUpdatePool() external {\n // There should be no harm allowing anyone to call this function.\n // It just updates the latest accRewardPerShare for the pool.\n updatePool();\n }\n\n /**\n * @dev Update the Liquidity Pool reward multiplier.\n * This locks in the accRewardPerShare from the last update block number to now.\n * Will fail if we do not have enough to pay everyone.\n * Always call updatePool whenever the balance changes!\n */\n function updatePool() internal {\n if (\n block.number <= pool.lastRewardBlock ||\n endBlock <= pool.lastRewardBlock\n ) {\n return;\n }\n\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (lpSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n uint256 incReward = getCampaignMultiplier(block.number).mul(\n rewardPerBlock\n );\n // we are of course assuming lpTokens are in 1e18 precision\n uint256 accRewardPerShare = pool.accRewardPerShare.add(\n incReward.divPrecisely(lpSupply)\n );\n\n pool.accRewardPerShare = accRewardPerShare;\n pool.lastRewardBlock = block.number;\n }\n\n /**\n * @dev Deposit LP tokens into contract, must be preapproved.\n * @param _amount Amount of LPToken to deposit.\n */\n function deposit(uint256 _amount) external {\n UserInfo storage user = userInfo[msg.sender];\n updatePool();\n if (_amount > 0) {\n user.amount = user.amount.add(_amount);\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = int256(\n _amount.mulTruncate(pool.accRewardPerShare)\n );\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Deposit(msg.sender, _amount);\n pool.lpToken.safeTransferFrom(\n address(msg.sender),\n address(this),\n _amount\n );\n }\n }\n\n /**\n * @dev Exit out of the contract completely, withdraw LP tokens and claim rewards\n */\n function exit() external {\n UserInfo storage user = userInfo[msg.sender];\n // withdraw everything\n _withdraw(user, user.amount, true);\n }\n\n /**\n * @dev Withdraw LP tokens from contract.\n * @param _amount Amount of LPToken to withdraw.\n * @param _claim Boolean do we want to claim our rewards or not\n */\n function withdraw(uint256 _amount, bool _claim) external {\n UserInfo storage user = userInfo[msg.sender];\n _withdraw(user, _amount, _claim);\n }\n\n function _withdraw(\n UserInfo storage user,\n uint256 _amount,\n bool _claim\n ) internal {\n require(user.amount >= _amount, \"withdraw: overflow\");\n updatePool();\n\n // newDebt is equal to the change in amount * accRewardPerShare (note accRewardPerShare is historic)\n int256 newDebt = -int256(_amount.mulTruncate(pool.accRewardPerShare));\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n uint256 pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n if (pending > 0) {\n reward.safeTransfer(msg.sender, pending);\n emit Claim(msg.sender, pending);\n }\n newDebt += int256(pending);\n }\n\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n }\n\n /**\n * @dev Claim all pending rewards up to current block\n */\n function claim() external {\n UserInfo storage user = userInfo[msg.sender];\n uint256 pending = _pendingRewards(user);\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n int256 debtDelta = int256(pending);\n user.rewardDebt += debtDelta;\n totalRewardDebt += debtDelta;\n reward.safeTransfer(msg.sender, pending);\n }\n }\n\n function subDebt(uint256 amount, int256 debt)\n internal\n pure\n returns (uint256 result)\n {\n if (debt < 0) {\n result = amount.add(uint256(-debt));\n } else {\n result = amount.sub(uint256(debt));\n }\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\ninterface CapitalPausable {\n function pauseCapital() external;\n\n function unpauseCapital() external;\n}\n\ncontract Timelock {\n using SafeMath for uint256;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n string signature,\n bytes data,\n uint256 eta\n );\n\n uint256 public constant GRACE_PERIOD = 3 days;\n uint256 public constant MINIMUM_DELAY = 1 minutes;\n uint256 public constant MAXIMUM_DELAY = 2 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n /**\n * @dev Throws if called by any account other than the Admin.\n */\n modifier onlyAdmin() {\n require(msg.sender == admin, \"Caller is not the admin\");\n _;\n }\n\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n function setDelay(uint256 delay_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setDelay: Call must come from Timelock.\"\n );\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::setDelay: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n function setPendingAdmin(address pendingAdmin_) public onlyAdmin {\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n function queueTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes32) {\n require(\n msg.sender == admin,\n \"Timelock::queueTransaction: Call must come from admin.\"\n );\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, signature, data, eta);\n return txHash;\n }\n\n function cancelTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n msg.sender == admin,\n \"Timelock::cancelTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, signature, data, eta);\n }\n\n function executeTransaction(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal returns (bytes memory) {\n require(\n msg.sender == admin,\n \"Timelock::executeTransaction: Call must come from admin.\"\n );\n\n bytes32 txHash = keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n );\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(\n bytes4(keccak256(bytes(signature))),\n data\n );\n }\n\n (bool success, bytes memory returnData) = target.call(callData);\n require(\n success,\n \"Timelock::executeTransaction: Transaction execution reverted.\"\n );\n\n emit ExecuteTransaction(txHash, target, signature, data, eta);\n\n return returnData;\n }\n\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n\n function pauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::pauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).pauseCapital();\n }\n\n function unpauseCapital(address target) external {\n require(\n msg.sender == admin,\n \"Timelock::unpauseCapital: Call must come from admin.\"\n );\n CapitalPausable(target).unpauseCapital();\n }\n}\n" + }, + "contracts/governance/Governor.sol": { + "content": "pragma solidity 0.5.11;\npragma experimental ABIEncoderV2;\n\nimport \"./../timelock/Timelock.sol\";\n\n// Modeled off of Compound's Governor Alpha\n// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol\ncontract Governor is Timelock {\n // @notice The total number of proposals\n uint256 public proposalCount;\n\n struct Proposal {\n // @notice Unique id for looking up a proposal\n uint256 id;\n // @notice Creator of the proposal\n address proposer;\n // @notice The timestamp that the proposal will be available for\n // execution, set once the vote succeeds\n uint256 eta;\n // @notice the ordered list of target addresses for calls to be made\n address[] targets;\n // @notice The ordered list of function signatures to be called\n string[] signatures;\n // @notice The ordered list of calldata to be passed to each call\n bytes[] calldatas;\n // @notice Flag marking whether the proposal has been executed\n bool executed;\n }\n\n // @notice The official record of all proposals ever proposed\n mapping(uint256 => Proposal) public proposals;\n\n // @notice An event emitted when a new proposal is created\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n string[] signatures,\n bytes[] calldatas,\n string description\n );\n\n // @notice An event emitted when a proposal has been queued in the Timelock\n event ProposalQueued(uint256 id, uint256 eta);\n\n // @notice An event emitted when a proposal has been executed in the Timelock\n event ProposalExecuted(uint256 id);\n\n // @notice An event emitted when a proposal has been cancelled\n event ProposalCancelled(uint256 id);\n\n uint256 public constant MAX_OPERATIONS = 16;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState { Pending, Queued, Expired, Executed }\n\n constructor(address admin_, uint256 delay_)\n public\n Timelock(admin_, delay_)\n {}\n\n /**\n * @notice Propose Governance call(s)\n * @param targets Ordered list of targeted addresses\n * @param signatures Orderd list of function signatures to be called\n * @param calldatas Orderded list of calldata to be passed with each call\n * @param description Description of the governance\n * @return uint256 id of the proposal\n */\n function propose(\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // Allow anyone to propose for now, since only admin can queue the\n // transaction it should be harmless, you just need to pay the gas\n require(\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"Governor::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"Governor::propose: must provide actions\");\n require(\n targets.length <= MAX_OPERATIONS,\n \"Governor::propose: too many actions\"\n );\n\n proposalCount++;\n Proposal memory newProposal = Proposal({\n id: proposalCount,\n proposer: msg.sender,\n eta: 0,\n targets: targets,\n signatures: signatures,\n calldatas: calldatas,\n executed: false\n });\n\n proposals[newProposal.id] = newProposal;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n signatures,\n calldatas,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Queue a proposal for execution\n * @param proposalId id of the proposal to queue\n */\n function queue(uint256 proposalId) public onlyAdmin {\n require(\n state(proposalId) == ProposalState.Pending,\n \"Governor::queue: proposal can only be queued if it is pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = block.timestamp.add(delay);\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalQueued(proposal.id, proposal.eta);\n }\n\n /**\n * @notice Get the state of a proposal\n * @param proposalId id of the proposal\n * @return ProposalState\n */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"Governor::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n if (proposal.executed) {\n return ProposalState.Executed;\n } else if (proposal.eta == 0) {\n return ProposalState.Pending;\n } else if (block.timestamp >= proposal.eta.add(GRACE_PERIOD)) {\n return ProposalState.Expired;\n } else {\n return ProposalState.Queued;\n }\n }\n\n function _queueOrRevert(\n address target,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !queuedTransactions[keccak256(\n abi.encode(target, signature, keccak256(data), eta)\n )],\n \"Governor::_queueOrRevert: proposal action already queued at eta\"\n );\n require(\n queuedTransactions[queueTransaction(target, signature, data, eta)],\n \"Governor::_queueOrRevert: failed to queue transaction\"\n );\n }\n\n /**\n * @notice Execute a proposal.\n * @param proposalId id of the proposal\n */\n function execute(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Queued,\n \"Governor::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n executeTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal.\n * @param proposalId id of the proposal\n */\n function cancel(uint256 proposalId) public onlyAdmin {\n ProposalState proposalState = state(proposalId);\n\n require(\n proposalState == ProposalState.Queued ||\n proposalState == ProposalState.Pending,\n \"Governor::execute: proposal can only be cancelled if it is queued or pending\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.eta = 1; // To mark the proposal as `Expired`\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n cancelTransaction(\n proposal.targets[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalCancelled(proposalId);\n }\n\n /**\n * @notice Get the actions that a proposal will take.\n * @param proposalId id of the proposal\n */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.signatures, p.calldatas);\n }\n}\n" + }, + "contracts/governance/InitializableGovernable.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport {\n Initializable\n} from \"@openzeppelin/upgrades/contracts/Initializable.sol\";\n\nimport { Governable } from \"./Governable.sol\";\n\ncontract InitializableGovernable is Governable, Initializable {\n function _initialize(address _newGovernor) internal {\n _changeGovernor(_newGovernor);\n }\n}\n" + }, + "contracts/crytic/PropertiesOUSDTransferable.sol": { + "content": "import \"./interfaces.sol\";\nimport \"../token/OUSD.sol\";\n\ncontract PropertiesOUSDTransferable is CryticInterface, OUSD {\n function init_total_supply() public returns (bool) {\n return\n this.totalSupply() >= 0 && this.totalSupply() == initialTotalSupply;\n }\n\n function init_owner_balance() public returns (bool) {\n return initialBalance_owner == this.balanceOf(crytic_owner);\n }\n\n function init_user_balance() public returns (bool) {\n return initialBalance_user == this.balanceOf(crytic_user);\n }\n\n function init_attacker_balance() public returns (bool) {\n return initialBalance_attacker == this.balanceOf(crytic_attacker);\n }\n\n function init_caller_balance() public returns (bool) {\n return this.balanceOf(msg.sender) > 0;\n }\n\n function init_total_supply_is_balances() public returns (bool) {\n return\n this.balanceOf(crytic_owner) +\n this.balanceOf(crytic_user) +\n this.balanceOf(crytic_attacker) ==\n this.totalSupply();\n }\n\n function crytic_zero_always_empty_ERC20Properties() public returns (bool) {\n return this.balanceOf(address(0x0)) == 0;\n }\n\n function crytic_approve_overwrites() public returns (bool) {\n bool approve_return;\n approve_return = approve(crytic_user, 10);\n require(approve_return);\n approve_return = approve(crytic_user, 20);\n require(approve_return);\n return this.allowance(msg.sender, crytic_user) == 20;\n }\n\n function crytic_less_than_total_ERC20Properties() public returns (bool) {\n return this.balanceOf(msg.sender) <= totalSupply();\n }\n\n function crytic_revert_transfer_to_zero_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n if (this.balanceOf(msg.sender) == 0) {\n revert();\n }\n return transfer(address(0x0), this.balanceOf(msg.sender));\n }\n\n function crytic_revert_transferFrom_to_zero_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n if (balance == 0) {\n revert();\n }\n approve(msg.sender, balance);\n return\n transferFrom(msg.sender, address(0x0), this.balanceOf(msg.sender));\n }\n\n function crytic_self_transferFrom_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool approve_return = approve(msg.sender, balance);\n bool transfer_return = transferFrom(msg.sender, msg.sender, balance);\n return\n (this.balanceOf(msg.sender) == balance) &&\n approve_return &&\n transfer_return;\n }\n\n function crytic_self_transferFrom_to_other_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool approve_return = approve(msg.sender, balance);\n address other = crytic_user;\n if (other == msg.sender) {\n other = crytic_owner;\n }\n bool transfer_return = transferFrom(msg.sender, other, balance);\n return\n (this.balanceOf(msg.sender) == 0) &&\n approve_return &&\n transfer_return;\n }\n\n function crytic_self_transfer_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n bool transfer_return = transfer(msg.sender, balance);\n return (this.balanceOf(msg.sender) == balance) && transfer_return;\n }\n\n function crytic_transfer_to_other_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n address other = crytic_user;\n if (other == msg.sender) {\n other = crytic_owner;\n }\n if (balance >= 1) {\n bool transfer_other = transfer(other, 1);\n return\n (this.balanceOf(msg.sender) == balance - 1) &&\n (this.balanceOf(other) >= 1) &&\n transfer_other;\n }\n return true;\n }\n\n function crytic_revert_transfer_to_user_ERC20PropertiesTransferable()\n public\n returns (bool)\n {\n uint256 balance = this.balanceOf(msg.sender);\n if (balance == (2**128 - 1)) return true;\n bool transfer_other = transfer(crytic_user, balance + 1);\n return transfer_other;\n }\n}\n" + }, + "contracts/crytic/interfaces.sol": { + "content": "contract CryticInterface {\n address internal crytic_owner = address(\n 0x627306090abaB3A6e1400e9345bC60c78a8BEf57\n );\n address internal crytic_user = address(\n 0xf17f52151EbEF6C7334FAD080c5704D77216b732\n );\n address internal crytic_attacker = address(\n 0xC5fdf4076b8F3A5357c5E395ab970B5B54098Fef\n );\n uint256 internal initialTotalSupply;\n uint256 internal initialBalance_owner;\n uint256 internal initialBalance_user;\n uint256 internal initialBalance_attacker;\n}\n" + }, + "contracts/crytic/TestOUSDTransferable.sol": { + "content": "import \"./PropertiesOUSDTransferable.sol\";\n\ncontract TestOUSDTransferable is PropertiesOUSDTransferable {\n constructor() public {\n // Existing addresses:\n // - crytic_owner: If the contract has an owner, it must be crytic_owner\n // - crytic_user: Legitimate user\n // - crytic_attacker: Attacker\n //\n // Add below a minimal configuration:\n // - crytic_owner must have some tokens\n // - crytic_user must have some tokens\n // - crytic_attacker must have some tokens\n\n rebasingCredits = 0;\n rebasingCreditsPerToken = 1e18;\n vaultAddress = crytic_owner;\n nonRebasingSupply = 0;\n\n initialTotalSupply = ~uint128(0);\n initialBalance_owner = initialTotalSupply / 3;\n _mint(crytic_owner, initialBalance_owner);\n initialBalance_user = initialTotalSupply / 3;\n _mint(crytic_user, initialBalance_user);\n initialBalance_attacker = initialTotalSupply / 3;\n _mint(crytic_attacker, initialBalance_attacker);\n }\n\n function initialize(\n string calldata _nameArg,\n string calldata _symbolArg,\n address _vaultAddress\n ) external {\n revert();\n } // We don't need to call initialize\n}\n" + }, + "contracts/mocks/MockDAI.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"DAI\";\n string public constant name = \"DAI\";\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"COMP\";\n string public constant name = \"COMP\";\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"CRV\";\n string public constant name = \"Curve DAO Token\";\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"../MintableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20 {\n uint256 public constant decimals = 18;\n string public constant symbol = \"3Crv\";\n string public constant name = \"Curve.fi DAI/USDC/USDT\";\n\n function mint(address to, uint256 value) public returns (bool) {\n _mint(to, value);\n return true;\n }\n\n function burnFrom(address from, uint256 value) public returns (bool) {\n _burn(from, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "pragma solidity 0.5.11;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICurveGauge } from \"../../strategies/ICurveGauge.sol\";\n\ncontract MockCurveGauge is ICurveGauge {\n mapping(address => uint256) private _balances;\n address lpToken;\n\n constructor(address _lpToken) public {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external {\n IERC20(lpToken).transfer(msg.sender, _value);\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/strategies/AaveStrategy.sol": { + "content": "pragma solidity 0.5.11;\n\n/**\n * @title OUSD Aave Strategy\n * @notice Investment strategy for investing stablecoins via Aave\n * @author Origin Protocol Inc\n */\nimport \"./IAave.sol\";\nimport {\n IERC20,\n InitializableAbstractStrategy\n} from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract AaveStrategy is InitializableAbstractStrategy {\n uint16 constant referralCode = 92;\n\n /**\n * @dev Deposit asset into Aave\n * @param _asset Address of asset to deposit\n * @param _amount Amount of asset to deposit\n * @return amountDeposited Amount of asset that was deposited\n */\n function deposit(address _asset, uint256 _amount)\n external\n onlyVault\n nonReentrant\n {\n require(_amount > 0, \"Must deposit something\");\n\n IAaveAToken aToken = _getATokenFor(_asset);\n emit Deposit(_asset, address(aToken), _amount);\n _getLendingPool().deposit(_asset, _amount, referralCode);\n }\n\n /**\n * @dev Withdraw asset from Aave\n * @param _recipient Address to receive withdrawn asset\n * @param _asset Address of asset to withdraw\n * @param _amount Amount of asset to withdraw\n * @return amountWithdrawn Amount of asset that was withdrawn\n */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n IAaveAToken aToken = _getATokenFor(_asset);\n emit Withdrawal(_asset, address(aToken), _amount);\n aToken.redeem(_amount);\n IERC20(_asset).safeTransfer(_recipient, _amount);\n }\n\n /**\n * @dev Remove all assets from platform and send them to Vault contract.\n */\n function withdrawAll() external onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of aToken\n IAaveAToken aToken = _getATokenFor(assetsMapped[i]);\n uint256 balance = aToken.balanceOf(address(this));\n if (balance > 0) {\n aToken.redeem(balance);\n // Transfer entire balance to Vault\n IERC20 asset = IERC20(assetsMapped[i]);\n asset.safeTransfer(\n vaultAddress,\n asset.balanceOf(address(this))\n );\n }\n }\n }\n\n /**\n * @dev Get the total asset value held in the platform\n * @param _asset Address of the asset\n * @return balance Total value of the asset in the platform\n */\n function checkBalance(address _asset)\n external\n view\n returns (uint256 balance)\n {\n // Balance is always with token aToken decimals\n IAaveAToken aToken = _getATokenFor(_asset);\n balance = aToken.balanceOf(address(this));\n }\n\n /**\n * @dev Retuns bool indicating whether asset is supported by strategy\n * @param _asset Address of the asset\n */\n function supportsAsset(address _asset) external view returns (bool) {\n return assetToPToken[_asset] != address(0);\n }\n\n /**\n * @dev Approve the spending of all assets by their corresponding aToken,\n * if for some reason is it necessary.\n */\n function safeApproveAllTokens() external onlyGovernor nonReentrant {\n uint256 assetCount = assetsMapped.length;\n address lendingPoolVault = _getLendingPoolCore();\n // approve the pool to spend the bAsset\n for (uint256 i = 0; i < assetCount; i++) {\n address asset = assetsMapped[i];\n // Safe approval\n IERC20(asset).safeApprove(lendingPoolVault, 0);\n IERC20(asset).safeApprove(lendingPoolVault, uint256(-1));\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / aTokens\n * We need to approve the aToken and give it permission to spend the asset\n * @param _asset Address of the asset to approve\n * @param _aToken This aToken has the approval approval\n */\n function _abstractSetPToken(address _asset, address _aToken) internal {\n address lendingPoolVault = _getLendingPoolCore();\n IERC20(_asset).safeApprove(lendingPoolVault, 0);\n IERC20(_asset).safeApprove(lendingPoolVault, uint256(-1));\n }\n\n /**\n * @dev Get the aToken wrapped in the ICERC20 interface for this asset.\n * Fails if the pToken doesn't exist in our mappings.\n * @param _asset Address of the asset\n * @return Corresponding aToken to this asset\n */\n function _getATokenFor(address _asset) internal view returns (IAaveAToken) {\n address aToken = assetToPToken[_asset];\n require(aToken != address(0), \"aToken does not exist\");\n return IAaveAToken(aToken);\n }\n\n /**\n * @dev Get the current address of the Aave lending pool, which is the gateway to\n * depositing.\n * @return Current lending pool implementation\n */\n function _getLendingPool() internal view returns (IAaveLendingPool) {\n address lendingPool = ILendingPoolAddressesProvider(platformAddress)\n .getLendingPool();\n require(lendingPool != address(0), \"Lending pool does not exist\");\n return IAaveLendingPool(lendingPool);\n }\n\n /**\n * @dev Get the current address of the Aave lending pool core, which stores all the\n * reserve tokens in its vault.\n * @return Current lending pool core address\n */\n function _getLendingPoolCore() internal view returns (address payable) {\n address payable lendingPoolCore = ILendingPoolAddressesProvider(\n platformAddress\n )\n .getLendingPoolCore();\n require(\n lendingPoolCore != address(uint160(address(0))),\n \"Lending pool core does not exist\"\n );\n return lendingPoolCore;\n }\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "pragma solidity 0.5.11;\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport {\n BaseUpgradeabilityProxy\n} from \"@openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is\n Governable,\n BaseUpgradeabilityProxy\n{\n /**\n * @dev Contract initializer with Governor enforcement\n * @param _logic Address of the initial implementation.\n * @param _initGovernor Address of the initial Governor.\n * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.\n */\n function initialize(\n address _logic,\n address _initGovernor,\n bytes memory _data\n ) public payable onlyGovernor {\n require(_implementation() == address(0));\n assert(\n IMPLEMENTATION_SLOT ==\n bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1)\n );\n _changeGovernor(_initGovernor);\n _setImplementation(_logic);\n if (_data.length > 0) {\n (bool success, ) = _logic.delegatecall(_data);\n require(success);\n }\n }\n\n /**\n * @return The address of the proxy admin/it's also the governor.\n */\n function admin() external view returns (address) {\n return _governor();\n }\n\n /**\n * @return The address of the implementation.\n */\n function implementation() external view returns (address) {\n return _implementation();\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy.\n * Only the admin can call this function.\n * @param newImplementation Address of the new implementation.\n */\n function upgradeTo(address newImplementation) external onlyGovernor {\n _upgradeTo(newImplementation);\n }\n\n /**\n * @dev Upgrade the backing implementation of the proxy and call a function\n * on the new implementation.\n * This is useful to initialize the proxied contract.\n * @param newImplementation Address of the new implementation.\n * @param data Data to send as msg.data in the low level call.\n * It should include the signature and the parameters of the function to be called, as described in\n * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data)\n external\n payable\n onlyGovernor\n {\n _upgradeTo(newImplementation);\n (bool success, ) = newImplementation.delegatecall(data);\n require(success);\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport './Proxy.sol';\nimport '../utils/Address.sol';\n\n/**\n * @title BaseUpgradeabilityProxy\n * @dev This contract implements a proxy that allows to change the\n * implementation address to which it will delegate.\n * Such a change is called an implementation upgrade.\n */\ncontract BaseUpgradeabilityProxy is Proxy {\n /**\n * @dev Emitted when the implementation is upgraded.\n * @param implementation Address of the new implementation.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return Address of the current implementation\n */\n function _implementation() internal view returns (address impl) {\n bytes32 slot = IMPLEMENTATION_SLOT;\n assembly {\n impl := sload(slot)\n }\n }\n\n /**\n * @dev Upgrades the proxy to a new implementation.\n * @param newImplementation Address of the new implementation.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation address of the proxy.\n * @param newImplementation Address of the new implementation.\n */\n function _setImplementation(address newImplementation) internal {\n require(OpenZeppelinUpgradesAddress.isContract(newImplementation), \"Cannot set a proxy implementation to a non-contract address\");\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/upgradeability/Proxy.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @title Proxy\n * @dev Implements delegation of calls to other contracts, with proper\n * forwarding of return values and bubbling of failures.\n * It defines a fallback function that delegates all calls to the address\n * returned by the abstract _implementation() internal function.\n */\ncontract Proxy {\n /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n function () payable external {\n _fallback();\n }\n\n /**\n * @return The Address of the implementation.\n */\n function _implementation() internal view returns (address);\n\n /**\n * @dev Delegates execution to an implementation contract.\n * This is a low level function that doesn't return to its internal call site.\n * It will return to the external caller whatever the implementation returns.\n * @param implementation Address to delegate.\n */\n function _delegate(address implementation) internal {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize)\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize)\n\n switch result\n // delegatecall returns 0 on error.\n case 0 { revert(0, returndatasize) }\n default { return(0, returndatasize) }\n }\n }\n\n /**\n * @dev Function that is run as the first thing in the fallback function.\n * Can be redefined in derived contracts to add functionality.\n * Redefinitions must call super._willFallback().\n */\n function _willFallback() internal {\n }\n\n /**\n * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\n}\n" + }, + "@openzeppelin/upgrades/contracts/utils/Address.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * Utility library of inline functions on addresses\n *\n * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol\n * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts\n * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the\n * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version.\n */\nlibrary OpenZeppelinUpgradesAddress {\n /**\n * Returns whether the target address is a contract\n * @dev This function will return false if invoked during the constructor of a contract,\n * as the code is not actually created until after the constructor finishes.\n * @param account address of the account to check\n * @return whether the target address is a contract\n */\n function isContract(address account) internal view returns (bool) {\n uint256 size;\n // XXX Currently there is no better way to check if there is a contract in an address\n // than to check the size of the code at that address.\n // See https://ethereum.stackexchange.com/a/14016/36603\n // for more details about how this works.\n // TODO Check this again before the Serenity release, because all addresses will be\n // contracts then.\n // solhint-disable-next-line no-inline-assembly\n assembly { size := extcodesize(account) }\n return size > 0;\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "pragma solidity 0.5.11;\n\nimport {\n InitializeGovernedUpgradeabilityProxy\n} from \"./InitializeGovernedUpgradeabilityProxy.sol\";\n\n/**\n * @notice OUSDProxy delegates calls to an OUSD implementation\n */\ncontract OUSDProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice VaultProxy delegates calls to a Vault implementation\n */\ncontract VaultProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice CompoundStrategyProxy delegates calls to a CompoundStrategy implementation\n */\ncontract CompoundStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js index 660de4a9d8..1cc25d1a60 100644 --- a/contracts/hardhat.config.js +++ b/contracts/hardhat.config.js @@ -209,30 +209,52 @@ task( const governor = await hre.ethers.getContract("Governor"); + const ognStakingProxy = await hre.ethers.getContract("OGNStakingProxy"); + const ognStaking = await hre.ethers.getContract("SingleAssetStaking"); + // // Addresses // console.log("\nContract addresses"); console.log("===================="); console.log(`OUSD proxy: ${ousdProxy.address}`); + console.log(`OUSD impl: ${await ousdProxy.implementation()}`); console.log(`OUSD: ${cOusd.address}`); console.log(`Vault proxy: ${vaultProxy.address}`); + console.log( + `Vault impl: ${await vaultProxy.implementation()}` + ); console.log(`Vault: ${cVault.address}`); console.log(`Vault core: ${vaultCore.address}`); console.log(`Vault admin: ${vaultAdmin.address}`); console.log(`AaveStrategy proxy: ${aaveProxy.address}`); + console.log(`AaveStrategy impl: ${await aaveProxy.implementation()}`); console.log(`AaveStrategy: ${cAaveStrategy.address}`); console.log(`CompoundStrategy proxy: ${compoundProxy.address}`); + console.log( + `CompoundStrategy impl: ${await compoundProxy.implementation()}` + ); console.log(`CompoundStrategy: ${cCompoundStrategy.address}`); if (!isMainnetOrRinkebyOrFork) { console.log(`CurveUSDCStrategy proxy: ${curveUSDCStrategyProxy.address}`); + console.log( + `CurveUSDCStrategy imply: ${await curveUSDCStrategyProxy.implementation()}` + ); console.log(`CurveUSDCStrategy: ${cCurveUSDCStrategy.address}`); console.log(`CurveUSDTStrategy proxy: ${curveUSDTStrategyProxy.address}`); + console.log( + `CurveUSDTStrategy impl: ${await curveUSDTStrategyProxy.implementation()}` + ); console.log(`CurveUSDTStrategy: ${cCurveUSDTStrategy.address}`); } console.log(`MixOracle: ${mixOracle.address}`); console.log(`ChainlinkOracle: ${chainlinkOracle.address}`); console.log(`Governor: ${governor.address}`); + console.log(`OGNStaking proxy: ${ognStakingProxy.address}`); + console.log( + `OGNStaking proxy impl: ${await ognStakingProxy.implementation()}` + ); + console.log(`OGNStaking: ${ognStaking.address}`); // // Governor diff --git a/contracts/utils/deploy.js b/contracts/utils/deploy.js index 136ea904cf..e66743ffe9 100644 --- a/contracts/utils/deploy.js +++ b/contracts/utils/deploy.js @@ -187,7 +187,7 @@ const sendProposal = async (proposalArgs, description) => { const governor = await ethers.getContract("Governor"); log(`Submitting proposal for ${description} to governor ${governor.address}`); - log(`Args: ${proposalArgs}`) + log(`Args: ${JSON.stringify(proposalArgs, null, 2)}`) await withConfirmation( governor .connect(sDeployer) diff --git a/dapp/network.mainnet.json b/dapp/network.mainnet.json index 1122535144..b46443322b 100644 --- a/dapp/network.mainnet.json +++ b/dapp/network.mainnet.json @@ -7137,7 +7137,7 @@ ] }, "SingleAssetStaking": { - "address": "0xF6c1a36a200c9aCc5046A86037Ffbe4e0eCb2d6a", + "address": "0x0Ed143d1D6d98f10db7151b66D76aA3956072b5a", "abi": [ { "constant": true, @@ -7749,6 +7749,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rate", + "type": "uint256" } ], "name": "Staked", @@ -7768,6 +7780,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" } ], "name": "Withdrawn", diff --git a/dapp/network.rinkeby.json b/dapp/network.rinkeby.json index 713e3168e9..c860b7c366 100644 --- a/dapp/network.rinkeby.json +++ b/dapp/network.rinkeby.json @@ -16119,7 +16119,7 @@ ] }, "SingleAssetStaking": { - "address": "0x13Cce8457Bd81b6935E760599dc523a95B9527e8", + "address": "0xc21B8c7F598bD0b4e383ec8C0AAE2b8519C2Bd65", "abi": [ { "constant": true, @@ -16731,6 +16731,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rate", + "type": "uint256" } ], "name": "Staked", @@ -16750,6 +16762,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" } ], "name": "Withdrawn", diff --git a/dapp/prod.network.json b/dapp/prod.network.json index 1122535144..b46443322b 100644 --- a/dapp/prod.network.json +++ b/dapp/prod.network.json @@ -7137,7 +7137,7 @@ ] }, "SingleAssetStaking": { - "address": "0xF6c1a36a200c9aCc5046A86037Ffbe4e0eCb2d6a", + "address": "0x0Ed143d1D6d98f10db7151b66D76aA3956072b5a", "abi": [ { "constant": true, @@ -7749,6 +7749,18 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rate", + "type": "uint256" } ], "name": "Staked", @@ -7768,6 +7780,12 @@ "internalType": "uint256", "name": "amount", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" } ], "name": "Withdrawn",