diff --git a/contracts/contracts/strategies/ConvexStrategy.sol b/contracts/contracts/strategies/ConvexStrategy.sol index 739e56dd3a..b2d9fe8936 100644 --- a/contracts/contracts/strategies/ConvexStrategy.sol +++ b/contracts/contracts/strategies/ConvexStrategy.sol @@ -31,7 +31,7 @@ contract ConvexStrategy is BaseCurveStrategy { address internal cvxDepositorAddress; address internal cvxRewardStakerAddress; - address internal cvxRewardTokenAddress; + address public cvxRewardTokenAddress; uint256 internal cvxDepositorPTokenId; /** diff --git a/contracts/deployments/mainnet/.migrations.json b/contracts/deployments/mainnet/.migrations.json index d0205f1373..3e8ea56690 100644 --- a/contracts/deployments/mainnet/.migrations.json +++ b/contracts/deployments/mainnet/.migrations.json @@ -27,5 +27,6 @@ "028_dai_default_aave": 1635960341, "029_convex": 1637241490, "030_staking_to_new_governor": 1637241517, - "031_staking_add_rescue": 1637241582 + "031_staking_add_rescue": 1637241582, + "032_convex_rewards": 1638551616 } \ No newline at end of file diff --git a/contracts/deployments/mainnet/ConvexStrategy.json b/contracts/deployments/mainnet/ConvexStrategy.json index 8e5a61cb71..36496a7341 100644 --- a/contracts/deployments/mainnet/ConvexStrategy.json +++ b/contracts/deployments/mainnet/ConvexStrategy.json @@ -1,6 +1,25 @@ { - "address": "0x08f3a0637851aA1B0E0750aA3d46E0E356f349aC", + "address": "0x16156a06bD1bd2d80134EA1Ee7e5FaEBDbFa20aa", "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_oldAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_newAddress", + "type": "address" + } + ], + "name": "CvxRewardTokenAddressUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -261,6 +280,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "cvxRewardTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -318,7 +350,7 @@ }, { "internalType": "address", - "name": "_crvRewardTokenAddress", + "name": "_cvxRewardTokenAddress", "type": "address" }, { @@ -457,6 +489,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_cvxRewardTokenAddress", + "type": "address" + } + ], + "name": "setCvxRewardTokenAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -595,42 +640,42 @@ "type": "function" } ], - "transactionHash": "0xa100b4d2644303d00b3003f783a26fb1ea52eb01f2b4549ab12bbe3500e6662e", + "transactionHash": "0x33a8af157a7cd887d506e20b8321a71d944505de159a1ca161cdf48685798862", "receipt": { "to": null, "from": "0x69e078EBc4631E1947F0c38Ef0357De7ED064644", - "contractAddress": "0x08f3a0637851aA1B0E0750aA3d46E0E356f349aC", - "transactionIndex": 99, - "gasUsed": "2614225", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000000000000000000800000000000000000000000000000000000004000000000000000000000000000000000000400010000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000020000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x17f6ceb5804639bad3648d013e04dc98bea652bf94f4b245a2f416ca5f8587b9", - "transactionHash": "0xa100b4d2644303d00b3003f783a26fb1ea52eb01f2b4549ab12bbe3500e6662e", + "contractAddress": "0x16156a06bD1bd2d80134EA1Ee7e5FaEBDbFa20aa", + "transactionIndex": 419, + "gasUsed": "2686955", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000006000000000000000000000000000000000000400010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000020000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200", + "blockHash": "0x998b7742dce1e57c6f756e00b9a400384724900e6c4a3dc159ca57b80ac33f60", + "transactionHash": "0x33a8af157a7cd887d506e20b8321a71d944505de159a1ca161cdf48685798862", "logs": [ { - "transactionIndex": 99, - "blockNumber": 13639482, - "transactionHash": "0xa100b4d2644303d00b3003f783a26fb1ea52eb01f2b4549ab12bbe3500e6662e", - "address": "0x08f3a0637851aA1B0E0750aA3d46E0E356f349aC", + "transactionIndex": 419, + "blockNumber": 13734790, + "transactionHash": "0x33a8af157a7cd887d506e20b8321a71d944505de159a1ca161cdf48685798862", + "address": "0x16156a06bD1bd2d80134EA1Ee7e5FaEBDbFa20aa", "topics": [ "0xc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000069e078ebc4631e1947f0c38ef0357de7ed064644" ], "data": "0x", - "logIndex": 86, - "blockHash": "0x17f6ceb5804639bad3648d013e04dc98bea652bf94f4b245a2f416ca5f8587b9" + "logIndex": 285, + "blockHash": "0x998b7742dce1e57c6f756e00b9a400384724900e6c4a3dc159ca57b80ac33f60" } ], - "blockNumber": 13639482, - "cumulativeGasUsed": "7192143", + "blockNumber": 13734790, + "cumulativeGasUsed": "20272919", "status": 1, "byzantium": true }, "args": [], - "solcInputHash": "cfb476f5893bbdf082d9f7aa8c26a863", - "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"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\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"_oldThreshold\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newThreshold\",\"type\":\"uint256\"}],\"name\":\"RewardLiquidationThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_oldAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newAddress\",\"type\":\"address\"}],\"name\":\"RewardTokenAddressUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vaultAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_crvRewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"_cvxDepositorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_cvxRewardStakerAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cvxDepositorPTokenId\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vaultAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardLiquidationThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRewardLiquidationThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"}],\"name\":\"setRewardTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"details\":\"Get the total asset value held in the platform\",\"params\":{\"_asset\":\"Address of the asset\"},\"returns\":{\"balance\":\" Total value of the asset in the platform\"}},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardToken()\":{\"details\":\"Collect accumulated CRV and send to Vault.\"},\"deposit(address,uint256)\":{\"details\":\"Deposit asset into the Curve 3Pool\",\"params\":{\"_amount\":\"Amount of asset to deposit\",\"_asset\":\"Address of asset to deposit\"}},\"depositAll()\":{\"details\":\"Deposit the entire balance of any supported asset into the Curve 3pool\"},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,address,address,address,address[],address[],address,address,uint256)\":{\"params\":{\"_assets\":\"Addresses of supported assets. MUST be passed in the same order as returned by coins on the pool contract, i.e. DAI, USDC, USDT\",\"_crvRewardTokenAddress\":\"Address of CRV *yes we get both*\",\"_cvxDepositorAddress\":\"Address of the Convex depositor(AKA booster) for this pool\",\"_cvxDepositorPTokenId\":\"Pid of the pool referred to by Depositor and staker\",\"_cvxRewardStakerAddress\":\"Address of the CRVX rewards staker\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_platformAddress\":\"Address of the Curve 3pool\",\"_rewardTokenAddress\":\"Address of CRVX\",\"_vaultAddress\":\"Address of the vault\"}},\"initialize(address,address,address,address[],address[])\":{\"details\":\"Internal initialize function, to set up initial internal state\",\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_platformAddress\":\"Generic platform address\",\"_rewardTokenAddress\":\"Address of reward token for platform\",\"_vaultAddress\":\"Address of the Vault\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"removePToken(uint256)\":{\"details\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\",\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"safeApproveAllTokens()\":{\"details\":\"Approve the spending of all assets by their corresponding pool tokens, if for some reason is it necessary.\"},\"setPTokenAddress(address,address)\":{\"details\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\",\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardLiquidationThreshold(uint256)\":{\"details\":\"Set the reward token liquidation threshold.\",\"params\":{\"_threshold\":\"Threshold amount in decimals of reward token that will cause the Vault to claim and withdrawAll on allocate() calls.\"}},\"setRewardTokenAddress(address)\":{\"details\":\"Set the reward token address.\",\"params\":{\"_rewardTokenAddress\":\"Address of the reward token\"}},\"supportsAsset(address)\":{\"details\":\"Retuns bool indicating whether asset is supported by strategy\",\"params\":{\"_asset\":\"Address of the asset\"}},\"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\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer token to governor. Intended for recovering tokens stuck in strategy contracts, i.e. mistaken sends.\",\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdraw(address,address,uint256)\":{\"details\":\"Withdraw asset from Curve 3Pool\",\"params\":{\"_amount\":\"Amount of asset to withdraw\",\"_asset\":\"Address of asset to withdraw\",\"_recipient\":\"Address to receive withdrawn asset\"}},\"withdrawAll()\":{\"details\":\"Remove all assets from platform and send them to Vault contract.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"initialize(address,address,address,address,address[],address[],address,address,uint256)\":{\"notice\":\"Initializer for setting up strategy internal state. This overrides the InitializableAbstractStrategy initializer as Curve strategies don't fit well within that abstraction.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/ConvexStrategy.sol\":\"ConvexStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\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(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) 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\":\"0x027b891937d20ccf213fdb9c31531574256de774bda99d3a70ecef6e1913ed2a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.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 IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\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. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x02348b2e4b9f3200c7e3907c5c2661643a6d8520e9f79939fbb9b4005a54894d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\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 // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\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 function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3336baae5cf23e94274d75336e2d412193be508504aee185e61dc7d58cd05c8a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\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) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\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 *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\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 *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\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 *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting 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 *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\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 * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting 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 *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\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 *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8666f020bd8fc9dc14f07e2ebc52b5f236ab4cdde7c77679b08cb2f94730043b\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\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 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 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() {\\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\":\"0x29d258134253bdaeeea64c17baaf6108ff50aec65ceddb7216ef3a948a88808c\",\"license\":\"agpl-3.0\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xcabd808c03076fa6fb5838a13210b2b99314d23842e0e3d5e55e0c1466e75212\",\"license\":\"agpl-3.0\"},\"contracts/strategies/BaseCurveStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Curve 3Pool Strategy\\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\\n * @author Origin Protocol Inc\\n */\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { ICurvePool } from \\\"./ICurvePool.sol\\\";\\nimport { ICRVMinter } from \\\"./ICRVMinter.sol\\\";\\nimport { IERC20, InitializableAbstractStrategy } from \\\"../utils/InitializableAbstractStrategy.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Helpers } from \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract BaseCurveStrategy is InitializableAbstractStrategy {\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n uint256 internal constant maxSlippage = 1e16; // 1%, same as the Curve UI\\n address internal pTokenAddress;\\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 override\\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 uint256 poolCoinIndex = _getCoinIndex(_asset);\\n // Set the amount on the asset we want to deposit\\n _amounts[poolCoinIndex] = _amount;\\n ICurvePool curvePool = ICurvePool(platformAddress);\\n uint256 assetDecimals = Helpers.getDecimals(_asset);\\n uint256 depositValue = _amount.scaleBy(18, assetDecimals).divPrecisely(\\n curvePool.get_virtual_price()\\n );\\n uint256 minMintAmount = depositValue.mulTruncate(\\n uint256(1e18) - maxSlippage\\n );\\n // Do the deposit to 3pool\\n curvePool.add_liquidity(_amounts, minMintAmount);\\n _lpDepositAll();\\n }\\n\\n function _lpDepositAll() internal virtual;\\n\\n /**\\n * @dev Deposit the entire balance of any supported asset into the Curve 3pool\\n */\\n function depositAll() external override onlyVault nonReentrant {\\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\\n uint256 depositValue = 0;\\n ICurvePool curvePool = ICurvePool(platformAddress);\\n uint256 curveVirtualPrice = curvePool.get_virtual_price();\\n\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n address assetAddress = assetsMapped[i];\\n uint256 balance = IERC20(assetAddress).balanceOf(address(this));\\n if (balance > 0) {\\n uint256 poolCoinIndex = _getCoinIndex(assetAddress);\\n // Set the amount on the asset we want to deposit\\n _amounts[poolCoinIndex] = balance;\\n uint256 assetDecimals = Helpers.getDecimals(assetAddress);\\n // Get value of deposit in Curve LP token to later determine\\n // the minMintAmount argument for add_liquidity\\n depositValue =\\n depositValue +\\n balance.scaleBy(18, assetDecimals).divPrecisely(\\n curveVirtualPrice\\n );\\n emit Deposit(assetAddress, address(platformAddress), balance);\\n }\\n }\\n\\n uint256 minMintAmount = depositValue.mulTruncate(\\n uint256(1e18) - maxSlippage\\n );\\n // Do the deposit to 3pool\\n curvePool.add_liquidity(_amounts, minMintAmount);\\n // Deposit into Gauge, the PToken is the same (3Crv) for all mapped\\n // assets, so just get the address from the first one\\n _lpDepositAll();\\n }\\n\\n function _lpWithdraw(uint256 numPTokens) internal virtual;\\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 override onlyVault nonReentrant {\\n require(_amount > 0, \\\"Invalid amount\\\");\\n\\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\\n\\n (uint256 contractPTokens, , uint256 totalPTokens) = _getTotalPTokens();\\n\\n uint256 coinIndex = _getCoinIndex(_asset);\\n int128 curveCoinIndex = int128(uint128(coinIndex));\\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 // Calculate how many platform tokens we need to withdraw the asset\\n // amount in the worst case (i.e withdrawing all LP tokens)\\n uint256 maxAmount = curvePool.calc_withdraw_one_coin(\\n totalPTokens,\\n curveCoinIndex\\n );\\n uint256 maxBurnedPTokens = (totalPTokens * _amount) / maxAmount;\\n\\n // Not enough in this contract or in the Gauge, can't proceed\\n require(totalPTokens > maxBurnedPTokens, \\\"Insufficient 3CRV balance\\\");\\n // We have enough LP tokens, make sure they are all on this contract\\n if (contractPTokens < maxBurnedPTokens) {\\n _lpWithdraw(maxBurnedPTokens - contractPTokens);\\n }\\n\\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\\n _amounts[coinIndex] = _amount;\\n curvePool.remove_liquidity_imbalance(_amounts, maxBurnedPTokens);\\n\\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 override onlyVaultOrGovernor nonReentrant {\\n // Withdraw all from Gauge\\n (, uint256 gaugePTokens, uint256 totalPTokens) = _getTotalPTokens();\\n _lpWithdraw(gaugePTokens);\\n // Withdraws are proportional to assets held by 3Pool\\n uint256[3] memory minWithdrawAmounts = [uint256(0), uint256(0), uint256(0)];\\n // Remove liquidity\\n ICurvePool threePool = ICurvePool(platformAddress);\\n threePool.remove_liquidity(totalPTokens, minWithdrawAmounts);\\n // Transfer assets out of Vault\\n // Note that Curve will provide all 3 of the assets in 3pool even if\\n // we have not set PToken addresses for all of them in this strategy\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n IERC20 asset = IERC20(threePool.coins(i));\\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\\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 public\\n view\\n override\\n returns (uint256 balance)\\n {\\n require(assetToPToken[_asset] != address(0), \\\"Unsupported asset\\\");\\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 ICurvePool curvePool = ICurvePool(platformAddress);\\n if (totalPTokens > 0) {\\n uint256 virtual_price = curvePool.get_virtual_price();\\n uint256 value = (totalPTokens * virtual_price) / 1e18;\\n uint256 assetDecimals = Helpers.getDecimals(_asset);\\n balance = value.scaleBy(assetDecimals, 18) / 3;\\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)\\n external\\n view\\n override\\n returns (bool)\\n {\\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()\\n external\\n override\\n onlyGovernor\\n nonReentrant\\n {\\n _approveBase();\\n // This strategy is a special case since it only supports one asset\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n _approveAsset(assetsMapped[i]);\\n }\\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 contractPTokens Amount of platform tokens in this contract\\n * @return gaugePTokens Amount of platform tokens staked in gauge\\n * @return totalPTokens Total amount of platform tokens in native decimals\\n */\\n function _getTotalPTokens()\\n internal\\n view\\n virtual\\n returns (\\n uint256 contractPTokens,\\n uint256 gaugePTokens,\\n uint256 totalPTokens\\n );\\n\\n /**\\n * @dev Call the necessary approvals for the Curve pool and gauge\\n * @param _asset Address of the asset\\n */\\n function _abstractSetPToken(address _asset, address _pToken)\\n internal\\n override\\n {\\n _approveAsset(_asset);\\n }\\n\\n function _approveAsset(address _asset) internal {\\n IERC20 asset = IERC20(_asset);\\n // 3Pool for asset (required for adding liquidity)\\n asset.safeApprove(platformAddress, 0);\\n asset.safeApprove(platformAddress, type(uint256).max);\\n }\\n\\n function _approveBase() internal virtual;\\n\\n /**\\n * @dev Get the index of the coin\\n */\\n function _getCoinIndex(address _asset) internal view returns (uint256) {\\n for (uint256 i = 0; i < 3; i++) {\\n if (assetsMapped[i] == _asset) return i;\\n }\\n revert(\\\"Invalid 3pool asset\\\");\\n }\\n}\\n\",\"keccak256\":\"0x18f01a1f1bec32585e2a4d38f1a30da5809aaee963c52347665e2a73a8b05af0\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ConvexStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Curve Convex Strategy\\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\\n * @author Origin Protocol Inc\\n */\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IRewardStaking } from \\\"./IRewardStaking.sol\\\";\\nimport { IConvexDeposits } from \\\"./IConvexDeposits.sol\\\";\\nimport { IERC20, BaseCurveStrategy } from \\\"./BaseCurveStrategy.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Helpers } from \\\"../utils/Helpers.sol\\\";\\n\\ncontract ConvexStrategy is BaseCurveStrategy {\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n event RewardTokenCollected(\\n address recipient,\\n address token,\\n uint256 amount\\n );\\n\\n address internal cvxDepositorAddress;\\n address internal cvxRewardStakerAddress;\\n address internal crvRewardTokenAddress;\\n uint256 internal cvxDepositorPTokenId;\\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 CRVX\\n * @param _crvRewardTokenAddress Address of CRV *yes we get both*\\n * @param _assets Addresses of supported assets. MUST be passed in the same\\n * order as returned by coins on the pool contract, i.e.\\n * DAI, USDC, USDT\\n * @param _pTokens Platform Token corresponding addresses\\n * @param _cvxDepositorAddress Address of the Convex depositor(AKA booster) for this pool\\n * @param _cvxRewardStakerAddress Address of the CRVX rewards staker\\n * @param _cvxDepositorPTokenId Pid of the pool referred to by Depositor and staker\\n */\\n function initialize(\\n address _platformAddress, // 3Pool address\\n address _vaultAddress,\\n address _rewardTokenAddress, // CRVX\\n address _crvRewardTokenAddress,\\n address[] calldata _assets,\\n address[] calldata _pTokens,\\n address _cvxDepositorAddress,\\n address _cvxRewardStakerAddress,\\n uint256 _cvxDepositorPTokenId\\n ) external onlyGovernor initializer {\\n require(_assets.length == 3, \\\"Must have exactly three assets\\\");\\n // Should be set prior to abstract initialize call otherwise\\n // abstractSetPToken calls will fail\\n cvxDepositorAddress = _cvxDepositorAddress;\\n cvxRewardStakerAddress = _cvxRewardStakerAddress;\\n cvxDepositorPTokenId = _cvxDepositorPTokenId;\\n crvRewardTokenAddress = _crvRewardTokenAddress;\\n pTokenAddress = _pTokens[0];\\n super._initialize(\\n _platformAddress,\\n _vaultAddress,\\n _rewardTokenAddress,\\n _assets,\\n _pTokens\\n );\\n _approveBase();\\n }\\n\\n function _lpDepositAll() internal override {\\n IERC20 pToken = IERC20(pTokenAddress);\\n // Deposit with staking\\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\\n cvxDepositorPTokenId,\\n pToken.balanceOf(address(this)),\\n true\\n );\\n require(success, \\\"Failed to deposit to Convex\\\");\\n }\\n\\n function _lpWithdraw(uint256 numPTokens) internal override {\\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\\n numPTokens,\\n true\\n );\\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 contractPTokens Amount of platform tokens in this contract\\n * @return gaugePTokens Amount of platform tokens staked in gauge\\n * @return totalPTokens Total amount of platform tokens in native decimals\\n */\\n function _getTotalPTokens()\\n internal\\n view\\n override\\n returns (\\n uint256 contractPTokens,\\n uint256 gaugePTokens, // gauge is a misnomer here, need a better name\\n uint256 totalPTokens\\n )\\n {\\n contractPTokens = IERC20(pTokenAddress).balanceOf(address(this));\\n gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\\n address(this)\\n ); //booster.poolInfo[pid].token.balanceOf(address(this)) Not needed if we always stake..\\n totalPTokens = contractPTokens + gaugePTokens;\\n }\\n\\n function _approveBase() internal override {\\n IERC20 pToken = IERC20(pTokenAddress);\\n // 3Pool for LP token (required for removing liquidity)\\n pToken.safeApprove(platformAddress, 0);\\n pToken.safeApprove(platformAddress, type(uint256).max);\\n // Gauge for LP token\\n pToken.safeApprove(cvxDepositorAddress, 0);\\n pToken.safeApprove(cvxDepositorAddress, type(uint256).max);\\n }\\n\\n /**\\n * @dev Collect accumulated CRV and send to Vault.\\n */\\n function collectRewardToken() external override onlyVault nonReentrant {\\n // Collect is done automatically with withdrawAndUnwrap\\n // Send CVX\\n IERC20 crvxToken = IERC20(rewardTokenAddress);\\n uint256 balance = crvxToken.balanceOf(address(this));\\n emit RewardTokenCollected(vaultAddress, rewardTokenAddress, balance);\\n crvxToken.safeTransfer(vaultAddress, balance);\\n // Send CRV\\n IERC20 crvToken = IERC20(crvRewardTokenAddress);\\n balance = crvToken.balanceOf(address(this));\\n emit RewardTokenCollected(vaultAddress, crvRewardTokenAddress, balance);\\n crvToken.safeTransfer(vaultAddress, balance);\\n }\\n}\\n\",\"keccak256\":\"0x74874fd28f5721993f7c7d7433da7c1ccb81995ab33727a9d6ff97894767ba74\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ICRVMinter.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface ICRVMinter {\\n function mint(address gaugeAddress) external;\\n}\\n\",\"keccak256\":\"0x2b688e8ee9b61faeaf9362bb3d5f21f622fc1a2c2eec81badde983e9a34b16c5\",\"license\":\"agpl-3.0\"},\"contracts/strategies/IConvexDeposits.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IConvexDeposits {\\n function deposit(\\n uint256 _pid,\\n uint256 _amount,\\n bool _stake\\n ) external returns (bool);\\n\\n function deposit(\\n uint256 _amount,\\n bool _lock,\\n address _stakeAddress\\n ) external;\\n}\\n\",\"keccak256\":\"0xaeb8e3858c2678e4e915c4f8f30d07941de7bc62139513f4443a041c3f224364\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ICurvePool.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface ICurvePool {\\n function get_virtual_price() external view returns (uint256);\\n\\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\\n\\n function balances(uint256) external view returns (uint256);\\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 remove_liquidity(\\n uint256 _amount,\\n uint256[3] calldata _minWithdrawAmounts\\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 function remove_liquidity_imbalance(\\n uint256[3] calldata _amounts,\\n uint256 maxBurnAmount\\n ) external;\\n}\\n\",\"keccak256\":\"0xd1faec85f8e7c5b29526b14770e9f4e7b29a542a7378c9b58574280b7bd94131\",\"license\":\"agpl-3.0\"},\"contracts/strategies/IRewardStaking.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IRewardStaking {\\n function stakeFor(address, uint256) external;\\n\\n function stake(uint256) external;\\n\\n function withdraw(uint256 amount, bool claim) external;\\n\\n function withdrawAndUnwrap(uint256 amount, bool claim) external;\\n\\n function earned(address account) external view returns (uint256);\\n\\n function getReward() external;\\n\\n function getReward(address _account, bool _claimExtras) external;\\n\\n function extraRewardsLength() external returns (uint256);\\n\\n function extraRewards(uint256 _pid) external returns (address);\\n\\n function rewardToken() external returns (address);\\n\\n function balanceOf(address account) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x06ca761842121009d3fe326fd61d3108fdad0ac2c95b94b723a322228578d8b2\",\"license\":\"agpl-3.0\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0x7ce41c7eacd2b6722029bd87759fe6e4d9b48a862277707737be82c94581b855\",\"license\":\"agpl-3.0\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nabstract contract Initializable {\\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 protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\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 uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xff2a83835ed8984e10338905bc31dbcaeeabdfc0e58d49257389cb1e5a3b9d8a\",\"license\":\"agpl-3.0\"},\"contracts/utils/InitializableAbstractStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\nabstract contract 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 event RewardTokenAddressUpdated(address _oldAddress, address _newAddress);\\n event RewardLiquidationThresholdUpdated(\\n uint256 _oldThreshold,\\n uint256 _newThreshold\\n );\\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 // Reserved for future expansion\\n int256[100] private _reserved;\\n\\n /**\\n * @dev Internal initialize function, to set up initial internal state\\n * @param _platformAddress Generic 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 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 Collect accumulated reward token and send to Vault.\\n */\\n function collectRewardToken() external virtual 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 /**\\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 emit RewardTokenAddressUpdated(rewardTokenAddress, _rewardTokenAddress);\\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 emit RewardLiquidationThresholdUpdated(\\n rewardLiquidationThreshold,\\n _threshold\\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)\\n internal\\n virtual;\\n\\n function safeApproveAllTokens() external virtual;\\n\\n /**\\n * @dev Deposit an 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 virtual;\\n\\n /**\\n * @dev Deposit balance of all supported assets into the platform\\n */\\n function depositAll() external virtual;\\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 virtual;\\n\\n /**\\n * @dev Withdraw all assets from strategy sending assets to Vault.\\n */\\n function withdrawAll() external virtual;\\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 virtual\\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 virtual returns (bool);\\n}\\n\",\"keccak256\":\"0xa8716794f09bca7859cb8bcc9c8e01acd73f326682e34cf3471fd9984fd30d18\",\"license\":\"agpl-3.0\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/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 to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n x = x.div(10**(from - to));\\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 9e36 / 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\":\"0x3dd9c475e374285f00f73351de859ed44b490f9989baee63c2d5db79b41aa9e8\",\"license\":\"agpl-3.0\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506100283360008051602062002e5e83398151915255565b60008051602062002e5e833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a3612dde80620000806000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c8063790fcf9f116100c3578063c7af33521161007c578063c7af3352146102e0578063cd3b0212146102e8578063d38bfff4146102fb578063d9caed121461030e578063dbe55e5614610321578063de5f62681461033457600080fd5b8063790fcf9f14610259578063853828b61461026c5780639136616a146102745780639a6acf2014610287578063aa388af61461029a578063ad1728cb146102d857600080fd5b80631a89a4d4116101155780631a89a4d4146101ee578063430bf08a1461020157806347e7ef24146102145780635653b414146102275780635d36b1901461023e5780635f5152261461024657600080fd5b80630242241d1461015d5780630c340a24146101675780630ed57b3a1461018c5780630fc3b4c41461019f5780631072cbea146101c8578063125f9e33146101db575b600080fd5b61016561033c565b005b61016f61058b565b6040516001600160a01b0390911681526020015b60405180910390f35b61016561019a366004612735565b6105a8565b61016f6101ad3660046126fb565b6035602052600090815260409020546001600160a01b031681565b6101656101d6366004612941565b6105da565b60375461016f906001600160a01b031681565b6101656101fc36600461276e565b61061a565b60345461016f906001600160a01b031681565b610165610222366004612941565b61080b565b61023060385481565b604051908152602001610183565b610165610a6e565b6102306102543660046126fb565b610b14565b610165610267366004612858565b610c5b565b610165610d62565b61016561028236600461298f565b610ff7565b6101656102953660046126fb565b6111c2565b6102c86102a83660046126fb565b6001600160a01b0390811660009081526035602052604090205416151590565b6040519015158152602001610183565b61016561124f565b6102c8611308565b6101656102f636600461298f565b611339565b6101656103093660046126fb565b61139e565b61016561031c366004612900565b611442565b60335461016f906001600160a01b031681565b61016561172a565b6034546001600160a01b0316331461036f5760405162461bcd60e51b815260040161036690612a77565b60405180910390fd5b600080516020612d69833981519152805460028114156103a15760405162461bcd60e51b815260040161036690612b33565b600282556037546040516370a0823160e01b81523060048201526001600160a01b039091169060009082906370a082319060240160206040518083038186803b1580156103ed57600080fd5b505afa158015610401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042591906129a8565b603454603754604080516001600160a01b03938416815292909116602083015281018290529091507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610494906001600160a01b03848116911683611a1a565b60a0546040516370a0823160e01b81523060048201526001600160a01b039091169081906370a082319060240160206040518083038186803b1580156104d957600080fd5b505afa1580156104ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051191906129a8565b60345460a054604080516001600160a01b03938416815292909116602083015281018290529092507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610580906001600160a01b03838116911684611a1a565b505050600182555050565b60006105a3600080516020612d898339815191525490565b905090565b6105b0611308565b6105cc5760405162461bcd60e51b815260040161036690612aae565b6105d68282611a82565b5050565b6105e2611308565b6105fe5760405162461bcd60e51b815260040161036690612aae565b6105d661060961058b565b6001600160a01b0384169083611a1a565b610622611308565b61063e5760405162461bcd60e51b815260040161036690612aae565b600054610100900460ff1680610657575060005460ff16155b6106735760405162461bcd60e51b815260040161036690612ae5565b600054610100900460ff16158015610695576000805461ffff19166101011790555b600387146106e55760405162461bcd60e51b815260206004820152601e60248201527f4d75737420686176652065786163746c792074687265652061737365747300006044820152606401610366565b609e80546001600160a01b038087166001600160a01b031992831617909255609f805486841690831617905560a184905560a08054928c1692909116919091179055858560008161073857610738612d3d565b905060200201602081019061074d91906126fb565b609d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055506107e38c8c8c8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d918291850190849080828437600092019190915250611be792505050565b6107eb611ccf565b80156107fd576000805461ff00191690555b505050505050505050505050565b6034546001600160a01b031633146108355760405162461bcd60e51b815260040161036690612a77565b600080516020612d69833981519152805460028114156108675760405162461bcd60e51b815260040161036690612b33565b60028255600083116108b45760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610366565b603354604080516001600160a01b03928316815260208101869052918616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a2610906612681565b600061091186611d45565b90508482826003811061092657610926612d3d565b60200201526033546001600160a01b0316600061094288611de1565b905060006109cc836001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b15801561098257600080fd5b505afa158015610996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ba91906129a8565b6109c68a601286611ed0565b90611f34565b905060006109f36109ec662386f26fc10000670de0b6b3a7640000612cb3565b8390611f5d565b604051634515cef360e01b81529091506001600160a01b03851690634515cef390610a249089908590600401612a29565b600060405180830381600087803b158015610a3e57600080fd5b505af1158015610a52573d6000803e3d6000fd5b50505050610a5e611f72565b5050505050506001825550505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610b095760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610366565b610b12336120cc565b565b6001600160a01b03818116600090815260356020526040812054909116610b715760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610366565b6000610b7b61218d565b6033549093506001600160a01b03169150508115610c54576000816001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0691906129a8565b90506000670de0b6b3a7640000610c1d8386612c94565b610c279190612b87565b90506000610c3487611de1565b90506003610c4483836012611ed0565b610c4e9190612b87565b95505050505b5050919050565b610c63611308565b610c7f5760405162461bcd60e51b815260040161036690612aae565b600054610100900460ff1680610c98575060005460ff16155b610cb45760405162461bcd60e51b815260040161036690612ae5565b600054610100900460ff16158015610cd6576000805461ffff19166101011790555b610d4688888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611be792505050565b8015610d58576000805461ff00191690555b5050505050505050565b6034546001600160a01b0316331480610d935750610d7e61058b565b6001600160a01b0316336001600160a01b0316145b610deb5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610366565b600080516020612d6983398151915280546002811415610e1d5760405162461bcd60e51b815260040161036690612b33565b60028255600080610e2c61218d565b9250925050610e3a8261229c565b6040805160608101825260008082526020820181905281830152603354915163ecb586a560e01b815290916001600160a01b031690819063ecb586a590610e879086908690600401612b5b565b600060405180830381600087803b158015610ea157600080fd5b505af1158015610eb5573d6000803e3d6000fd5b5050505060005b603654811015610fea5760405163c661065760e01b8152600481018290526000906001600160a01b0384169063c66106579060240160206040518083038186803b158015610f0957600080fd5b505afa158015610f1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f419190612718565b6034546040516370a0823160e01b8152306004820152919250610fd7916001600160a01b03918216918416906370a082319060240160206040518083038186803b158015610f8e57600080fd5b505afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906129a8565b6001600160a01b0384169190611a1a565b5080610fe281612cf6565b915050610ebc565b5050505050600182555050565b610fff611308565b61101b5760405162461bcd60e51b815260040161036690612aae565b603654811061105c5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610366565b60006036828154811061107157611071612d3d565b60009182526020808320909101546001600160a01b039081168084526035909252604090922054603654919350909116906110ae90600190612cb3565b83101561113057603680546110c590600190612cb3565b815481106110d5576110d5612d3d565b600091825260209091200154603680546001600160a01b03909216918590811061110157611101612d3d565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b603680548061114157611141612d27565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526035855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6111ca611308565b6111e65760405162461bcd60e51b815260040161036690612aae565b603754604080516001600160a01b03928316815291831660208301527f6000690cf6fd1e69830cc1142bc52655402f4a58db681849f61c3c8fb322ff8a910160405180910390a1603780546001600160a01b0319166001600160a01b0392909216919091179055565b611257611308565b6112735760405162461bcd60e51b815260040161036690612aae565b600080516020612d69833981519152805460028114156112a55760405162461bcd60e51b815260040161036690612b33565b600282556112b1611ccf565b60005b603654811015611300576112ee603682815481106112d4576112d4612d3d565b6000918252602090912001546001600160a01b0316612304565b806112f881612cf6565b9150506112b4565b505060019055565b6000611320600080516020612d898339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611341611308565b61135d5760405162461bcd60e51b815260040161036690612aae565b60385460408051918252602082018390527f01538952e8f491e3569a11bf3935ca2fa917ea85ec938dac52e696fbb76d8cc6910160405180910390a1603855565b6113a6611308565b6113c25760405162461bcd60e51b815260040161036690612aae565b6113ea817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661140a600080516020612d898339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6034546001600160a01b0316331461146c5760405162461bcd60e51b815260040161036690612a77565b600080516020612d698339815191528054600281141561149e5760405162461bcd60e51b815260040161036690612b33565b60028255600083116114e35760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610366565b6001600160a01b0384811660008181526035602090815260409182902054825194168452830186905290917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a260008061154461218d565b9250509150600061155487611d45565b60335460405163cc2b27d760e01b815260048101859052600f83900b602482015291925082916001600160a01b0390911690600090829063cc2b27d79060440160206040518083038186803b1580156115ac57600080fd5b505afa1580156115c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e491906129a8565b90506000816115f38b88612c94565b6115fd9190612b87565b905080861161164e5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420334352562062616c616e6365000000000000006044820152606401610366565b80871015611668576116686116638883612cb3565b61229c565b600060405180606001604052806000815260200160008152602001600081525090508a81876003811061169d5761169d612d3d565b60200201526040516327f6ba8360e21b81526001600160a01b03851690639fdaea0c906116d09084908690600401612a29565b600060405180830381600087803b1580156116ea57600080fd5b505af11580156116fe573d6000803e3d6000fd5b50611717925050506001600160a01b038d168e8d611a1a565b5050505050505050600182555050505050565b6034546001600160a01b031633146117545760405162461bcd60e51b815260040161036690612a77565b600080516020612d69833981519152805460028114156117865760405162461bcd60e51b815260040161036690612b33565b6002825560408051606081018252600080825260208083018290528284018290526033548451630176f71760e71b81529451939492936001600160a01b03909116928492849263bb7b8b80926004808201939291829003018186803b1580156117ee57600080fd5b505afa158015611802573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182691906129a8565b905060005b6036548110156119895760006036828154811061184a5761184a612d3d565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561189857600080fd5b505afa1580156118ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d091906129a8565b905080156119745760006118e383611d45565b9050818882600381106118f8576118f8612d3d565b6020020152600061190884611de1565b905061191a866109c685601285611ed0565b6119249089612b6f565b603354604080516001600160a01b03928316815260208101879052929a50908616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a250505b5050808061198190612cf6565b91505061182b565b5060006119af6119a8662386f26fc10000670de0b6b3a7640000612cb3565b8590611f5d565b604051634515cef360e01b81529091506001600160a01b03841690634515cef3906119e09088908590600401612a29565b600060405180830381600087803b1580156119fa57600080fd5b505af1158015611a0e573d6000803e3d6000fd5b50505050610fea611f72565b6040516001600160a01b038316602482015260448101829052611a7d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261233d565b505050565b6001600160a01b038281166000908152603560205260409020541615611adf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610366565b6001600160a01b03821615801590611aff57506001600160a01b03811615155b611b3f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610366565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a26105d6828261240f565b603380546001600160a01b038088166001600160a01b031992831617909255603480548784169083161790556037805492861692909116919091179055815181518114611c6d5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610366565b60005b81811015611cc657611cb4848281518110611c8d57611c8d612d3d565b6020026020010151848381518110611ca757611ca7612d3d565b6020026020010151611a82565b80611cbe81612cf6565b915050611c70565b50505050505050565b609d546033546001600160a01b0391821691611cef918391166000612418565b603354611d0b906001600160a01b038381169116600019612418565b609e54611d26906001600160a01b0383811691166000612418565b609e54611d42906001600160a01b038381169116600019612418565b50565b6000805b6003811015611da257826001600160a01b031660368281548110611d6f57611d6f612d3d565b6000918252602090912001546001600160a01b03161415611d905792915050565b80611d9a81612cf6565b915050611d49565b5060405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59080cdc1bdbdb08185cdcd95d606a1b6044820152606401610366565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1d57600080fd5b505afa158015611e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5591906129c1565b60ff16905060048110158015611e6c575060128111155b611eca5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610366565b92915050565b600081831115611f0057611ef9611ee78385612cb3565b611ef290600a612bec565b859061253c565b9350611f2a565b81831015611f2a57611f27611f158484612cb3565b611f2090600a612bec565b8590612548565b93505b50825b9392505050565b600080611f4984670de0b6b3a764000061253c565b9050611f558184612548565b949350505050565b6000611f2d8383670de0b6b3a7640000612554565b609d54609e5460a1546040516370a0823160e01b81523060048201526001600160a01b039384169360009316916343a0d0669185906370a082319060240160206040518083038186803b158015611fc857600080fd5b505afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906129a8565b6040516001600160e01b031960e085901b1681526004810192909252602482015260016044820152606401602060405180830381600087803b15801561204557600080fd5b505af1158015612059573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207d919061296d565b9050806105d65760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f206465706f73697420746f20436f6e76657800000000006044820152606401610366565b6001600160a01b0381166121225760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610366565b806001600160a01b0316612142600080516020612d898339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611d4281600080516020612d8983398151915255565b609d546040516370a0823160e01b8152306004820152600091829182916001600160a01b0316906370a082319060240160206040518083038186803b1580156121d557600080fd5b505afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d91906129a8565b609f546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a082319060240160206040518083038186803b15801561225157600080fd5b505afa158015612265573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228991906129a8565b91506122958284612b6f565b9050909192565b609f54604051636197390160e11b815260048101839052600160248201526001600160a01b039091169063c32e720290604401600060405180830381600087803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b5050505050565b6033548190612321906001600160a01b0380841691166000612418565b6033546105d6906001600160a01b038381169116600019612418565b6000612392826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166125769092919063ffffffff16565b805190915015611a7d57808060200190518101906123b0919061296d565b611a7d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610366565b6105d682612304565b8015806124a15750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561246757600080fd5b505afa15801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f91906129a8565b155b61250c5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610366565b6040516001600160a01b038316602482015260448101829052611a7d90849063095ea7b360e01b90606401611a46565b6000611f2d8284612c94565b6000611f2d8284612b87565b600080612561858561253c565b905061256d8184612548565b95945050505050565b6060611f55848460008585843b6125cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610366565b600080866001600160a01b031685876040516125eb9190612a0d565b60006040518083038185875af1925050503d8060008114612628576040519150601f19603f3d011682016040523d82523d6000602084013e61262d565b606091505b509150915061263d828286612648565b979650505050505050565b60608315612657575081611f2d565b8251156126675782518084602001fd5b8160405162461bcd60e51b81526004016103669190612a44565b60405180606001604052806003906020820280368337509192915050565b80356126aa81612d53565b919050565b60008083601f8401126126c157600080fd5b50813567ffffffffffffffff8111156126d957600080fd5b6020830191508360208260051b85010111156126f457600080fd5b9250929050565b60006020828403121561270d57600080fd5b8135611f2d81612d53565b60006020828403121561272a57600080fd5b8151611f2d81612d53565b6000806040838503121561274857600080fd5b823561275381612d53565b9150602083013561276381612d53565b809150509250929050565b60008060008060008060008060008060006101208c8e03121561279057600080fd5b61279a8c35612d53565b8b359a506127ab60208d0135612d53565b60208c013599506127be60408d0161269f565b98506127cc60608d0161269f565b975067ffffffffffffffff8060808e013511156127e857600080fd5b6127f88e60808f01358f016126af565b909850965060a08d013581101561280e57600080fd5b5061281f8d60a08e01358e016126af565b909550935061283060c08d0161269f565b925061283e60e08d0161269f565b91506101008c013590509295989b509295989b9093969950565b600080600080600080600060a0888a03121561287357600080fd5b873561287e81612d53565b9650602088013561288e81612d53565b9550604088013561289e81612d53565b9450606088013567ffffffffffffffff808211156128bb57600080fd5b6128c78b838c016126af565b909650945060808a01359150808211156128e057600080fd5b506128ed8a828b016126af565b989b979a50959850939692959293505050565b60008060006060848603121561291557600080fd5b833561292081612d53565b9250602084013561293081612d53565b929592945050506040919091013590565b6000806040838503121561295457600080fd5b823561295f81612d53565b946020939093013593505050565b60006020828403121561297f57600080fd5b81518015158114611f2d57600080fd5b6000602082840312156129a157600080fd5b5035919050565b6000602082840312156129ba57600080fd5b5051919050565b6000602082840312156129d357600080fd5b815160ff81168114611f2d57600080fd5b8060005b6003811015612a075781518452602093840193909101906001016129e8565b50505050565b60008251612a1f818460208701612cca565b9190910192915050565b60808101612a3782856129e4565b8260608301529392505050565b6020815260008251806020840152612a63816040850160208701612cca565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b82815260808101611f2d60208301846129e4565b60008219821115612b8257612b82612d11565b500190565b600082612ba457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612be4578160001904821115612bca57612bca612d11565b80851615612bd757918102915b93841c9390800290612bae565b509250929050565b6000611f2d8383600082612c0257506001611eca565b81612c0f57506000611eca565b8160018114612c255760028114612c2f57612c4b565b6001915050611eca565b60ff841115612c4057612c40612d11565b50506001821b611eca565b5060208310610133831016604e8410600b8410161715612c6e575081810a611eca565b612c788383612ba9565b8060001904821115612c8c57612c8c612d11565b029392505050565b6000816000190483118215151615612cae57612cae612d11565b500290565b600082821015612cc557612cc5612d11565b500390565b60005b83811015612ce5578181015183820152602001612ccd565b83811115612a075750506000910152565b6000600019821415612d0a57612d0a612d11565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114611d4257600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e3238969a2d8ae5ccdfe5ad9a29407b821c3f5f49c48082df126d6e25f86062264736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101585760003560e01c8063790fcf9f116100c3578063c7af33521161007c578063c7af3352146102e0578063cd3b0212146102e8578063d38bfff4146102fb578063d9caed121461030e578063dbe55e5614610321578063de5f62681461033457600080fd5b8063790fcf9f14610259578063853828b61461026c5780639136616a146102745780639a6acf2014610287578063aa388af61461029a578063ad1728cb146102d857600080fd5b80631a89a4d4116101155780631a89a4d4146101ee578063430bf08a1461020157806347e7ef24146102145780635653b414146102275780635d36b1901461023e5780635f5152261461024657600080fd5b80630242241d1461015d5780630c340a24146101675780630ed57b3a1461018c5780630fc3b4c41461019f5780631072cbea146101c8578063125f9e33146101db575b600080fd5b61016561033c565b005b61016f61058b565b6040516001600160a01b0390911681526020015b60405180910390f35b61016561019a366004612735565b6105a8565b61016f6101ad3660046126fb565b6035602052600090815260409020546001600160a01b031681565b6101656101d6366004612941565b6105da565b60375461016f906001600160a01b031681565b6101656101fc36600461276e565b61061a565b60345461016f906001600160a01b031681565b610165610222366004612941565b61080b565b61023060385481565b604051908152602001610183565b610165610a6e565b6102306102543660046126fb565b610b14565b610165610267366004612858565b610c5b565b610165610d62565b61016561028236600461298f565b610ff7565b6101656102953660046126fb565b6111c2565b6102c86102a83660046126fb565b6001600160a01b0390811660009081526035602052604090205416151590565b6040519015158152602001610183565b61016561124f565b6102c8611308565b6101656102f636600461298f565b611339565b6101656103093660046126fb565b61139e565b61016561031c366004612900565b611442565b60335461016f906001600160a01b031681565b61016561172a565b6034546001600160a01b0316331461036f5760405162461bcd60e51b815260040161036690612a77565b60405180910390fd5b600080516020612d69833981519152805460028114156103a15760405162461bcd60e51b815260040161036690612b33565b600282556037546040516370a0823160e01b81523060048201526001600160a01b039091169060009082906370a082319060240160206040518083038186803b1580156103ed57600080fd5b505afa158015610401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042591906129a8565b603454603754604080516001600160a01b03938416815292909116602083015281018290529091507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610494906001600160a01b03848116911683611a1a565b60a0546040516370a0823160e01b81523060048201526001600160a01b039091169081906370a082319060240160206040518083038186803b1580156104d957600080fd5b505afa1580156104ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051191906129a8565b60345460a054604080516001600160a01b03938416815292909116602083015281018290529092507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610580906001600160a01b03838116911684611a1a565b505050600182555050565b60006105a3600080516020612d898339815191525490565b905090565b6105b0611308565b6105cc5760405162461bcd60e51b815260040161036690612aae565b6105d68282611a82565b5050565b6105e2611308565b6105fe5760405162461bcd60e51b815260040161036690612aae565b6105d661060961058b565b6001600160a01b0384169083611a1a565b610622611308565b61063e5760405162461bcd60e51b815260040161036690612aae565b600054610100900460ff1680610657575060005460ff16155b6106735760405162461bcd60e51b815260040161036690612ae5565b600054610100900460ff16158015610695576000805461ffff19166101011790555b600387146106e55760405162461bcd60e51b815260206004820152601e60248201527f4d75737420686176652065786163746c792074687265652061737365747300006044820152606401610366565b609e80546001600160a01b038087166001600160a01b031992831617909255609f805486841690831617905560a184905560a08054928c1692909116919091179055858560008161073857610738612d3d565b905060200201602081019061074d91906126fb565b609d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055506107e38c8c8c8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d918291850190849080828437600092019190915250611be792505050565b6107eb611ccf565b80156107fd576000805461ff00191690555b505050505050505050505050565b6034546001600160a01b031633146108355760405162461bcd60e51b815260040161036690612a77565b600080516020612d69833981519152805460028114156108675760405162461bcd60e51b815260040161036690612b33565b60028255600083116108b45760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610366565b603354604080516001600160a01b03928316815260208101869052918616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a2610906612681565b600061091186611d45565b90508482826003811061092657610926612d3d565b60200201526033546001600160a01b0316600061094288611de1565b905060006109cc836001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b15801561098257600080fd5b505afa158015610996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ba91906129a8565b6109c68a601286611ed0565b90611f34565b905060006109f36109ec662386f26fc10000670de0b6b3a7640000612cb3565b8390611f5d565b604051634515cef360e01b81529091506001600160a01b03851690634515cef390610a249089908590600401612a29565b600060405180830381600087803b158015610a3e57600080fd5b505af1158015610a52573d6000803e3d6000fd5b50505050610a5e611f72565b5050505050506001825550505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610b095760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610366565b610b12336120cc565b565b6001600160a01b03818116600090815260356020526040812054909116610b715760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b6044820152606401610366565b6000610b7b61218d565b6033549093506001600160a01b03169150508115610c54576000816001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0691906129a8565b90506000670de0b6b3a7640000610c1d8386612c94565b610c279190612b87565b90506000610c3487611de1565b90506003610c4483836012611ed0565b610c4e9190612b87565b95505050505b5050919050565b610c63611308565b610c7f5760405162461bcd60e51b815260040161036690612aae565b600054610100900460ff1680610c98575060005460ff16155b610cb45760405162461bcd60e51b815260040161036690612ae5565b600054610100900460ff16158015610cd6576000805461ffff19166101011790555b610d4688888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611be792505050565b8015610d58576000805461ff00191690555b5050505050505050565b6034546001600160a01b0316331480610d935750610d7e61058b565b6001600160a01b0316336001600160a01b0316145b610deb5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610366565b600080516020612d6983398151915280546002811415610e1d5760405162461bcd60e51b815260040161036690612b33565b60028255600080610e2c61218d565b9250925050610e3a8261229c565b6040805160608101825260008082526020820181905281830152603354915163ecb586a560e01b815290916001600160a01b031690819063ecb586a590610e879086908690600401612b5b565b600060405180830381600087803b158015610ea157600080fd5b505af1158015610eb5573d6000803e3d6000fd5b5050505060005b603654811015610fea5760405163c661065760e01b8152600481018290526000906001600160a01b0384169063c66106579060240160206040518083038186803b158015610f0957600080fd5b505afa158015610f1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f419190612718565b6034546040516370a0823160e01b8152306004820152919250610fd7916001600160a01b03918216918416906370a082319060240160206040518083038186803b158015610f8e57600080fd5b505afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc691906129a8565b6001600160a01b0384169190611a1a565b5080610fe281612cf6565b915050610ebc565b5050505050600182555050565b610fff611308565b61101b5760405162461bcd60e51b815260040161036690612aae565b603654811061105c5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610366565b60006036828154811061107157611071612d3d565b60009182526020808320909101546001600160a01b039081168084526035909252604090922054603654919350909116906110ae90600190612cb3565b83101561113057603680546110c590600190612cb3565b815481106110d5576110d5612d3d565b600091825260209091200154603680546001600160a01b03909216918590811061110157611101612d3d565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b603680548061114157611141612d27565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526035855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b6111ca611308565b6111e65760405162461bcd60e51b815260040161036690612aae565b603754604080516001600160a01b03928316815291831660208301527f6000690cf6fd1e69830cc1142bc52655402f4a58db681849f61c3c8fb322ff8a910160405180910390a1603780546001600160a01b0319166001600160a01b0392909216919091179055565b611257611308565b6112735760405162461bcd60e51b815260040161036690612aae565b600080516020612d69833981519152805460028114156112a55760405162461bcd60e51b815260040161036690612b33565b600282556112b1611ccf565b60005b603654811015611300576112ee603682815481106112d4576112d4612d3d565b6000918252602090912001546001600160a01b0316612304565b806112f881612cf6565b9150506112b4565b505060019055565b6000611320600080516020612d898339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611341611308565b61135d5760405162461bcd60e51b815260040161036690612aae565b60385460408051918252602082018390527f01538952e8f491e3569a11bf3935ca2fa917ea85ec938dac52e696fbb76d8cc6910160405180910390a1603855565b6113a6611308565b6113c25760405162461bcd60e51b815260040161036690612aae565b6113ea817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661140a600080516020612d898339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6034546001600160a01b0316331461146c5760405162461bcd60e51b815260040161036690612a77565b600080516020612d698339815191528054600281141561149e5760405162461bcd60e51b815260040161036690612b33565b60028255600083116114e35760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610366565b6001600160a01b0384811660008181526035602090815260409182902054825194168452830186905290917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a260008061154461218d565b9250509150600061155487611d45565b60335460405163cc2b27d760e01b815260048101859052600f83900b602482015291925082916001600160a01b0390911690600090829063cc2b27d79060440160206040518083038186803b1580156115ac57600080fd5b505afa1580156115c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e491906129a8565b90506000816115f38b88612c94565b6115fd9190612b87565b905080861161164e5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420334352562062616c616e6365000000000000006044820152606401610366565b80871015611668576116686116638883612cb3565b61229c565b600060405180606001604052806000815260200160008152602001600081525090508a81876003811061169d5761169d612d3d565b60200201526040516327f6ba8360e21b81526001600160a01b03851690639fdaea0c906116d09084908690600401612a29565b600060405180830381600087803b1580156116ea57600080fd5b505af11580156116fe573d6000803e3d6000fd5b50611717925050506001600160a01b038d168e8d611a1a565b5050505050505050600182555050505050565b6034546001600160a01b031633146117545760405162461bcd60e51b815260040161036690612a77565b600080516020612d69833981519152805460028114156117865760405162461bcd60e51b815260040161036690612b33565b6002825560408051606081018252600080825260208083018290528284018290526033548451630176f71760e71b81529451939492936001600160a01b03909116928492849263bb7b8b80926004808201939291829003018186803b1580156117ee57600080fd5b505afa158015611802573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182691906129a8565b905060005b6036548110156119895760006036828154811061184a5761184a612d3d565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561189857600080fd5b505afa1580156118ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d091906129a8565b905080156119745760006118e383611d45565b9050818882600381106118f8576118f8612d3d565b6020020152600061190884611de1565b905061191a866109c685601285611ed0565b6119249089612b6f565b603354604080516001600160a01b03928316815260208101879052929a50908616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a250505b5050808061198190612cf6565b91505061182b565b5060006119af6119a8662386f26fc10000670de0b6b3a7640000612cb3565b8590611f5d565b604051634515cef360e01b81529091506001600160a01b03841690634515cef3906119e09088908590600401612a29565b600060405180830381600087803b1580156119fa57600080fd5b505af1158015611a0e573d6000803e3d6000fd5b50505050610fea611f72565b6040516001600160a01b038316602482015260448101829052611a7d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261233d565b505050565b6001600160a01b038281166000908152603560205260409020541615611adf5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610366565b6001600160a01b03821615801590611aff57506001600160a01b03811615155b611b3f5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610366565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a26105d6828261240f565b603380546001600160a01b038088166001600160a01b031992831617909255603480548784169083161790556037805492861692909116919091179055815181518114611c6d5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610366565b60005b81811015611cc657611cb4848281518110611c8d57611c8d612d3d565b6020026020010151848381518110611ca757611ca7612d3d565b6020026020010151611a82565b80611cbe81612cf6565b915050611c70565b50505050505050565b609d546033546001600160a01b0391821691611cef918391166000612418565b603354611d0b906001600160a01b038381169116600019612418565b609e54611d26906001600160a01b0383811691166000612418565b609e54611d42906001600160a01b038381169116600019612418565b50565b6000805b6003811015611da257826001600160a01b031660368281548110611d6f57611d6f612d3d565b6000918252602090912001546001600160a01b03161415611d905792915050565b80611d9a81612cf6565b915050611d49565b5060405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59080cdc1bdbdb08185cdcd95d606a1b6044820152606401610366565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1d57600080fd5b505afa158015611e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5591906129c1565b60ff16905060048110158015611e6c575060128111155b611eca5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b6064820152608401610366565b92915050565b600081831115611f0057611ef9611ee78385612cb3565b611ef290600a612bec565b859061253c565b9350611f2a565b81831015611f2a57611f27611f158484612cb3565b611f2090600a612bec565b8590612548565b93505b50825b9392505050565b600080611f4984670de0b6b3a764000061253c565b9050611f558184612548565b949350505050565b6000611f2d8383670de0b6b3a7640000612554565b609d54609e5460a1546040516370a0823160e01b81523060048201526001600160a01b039384169360009316916343a0d0669185906370a082319060240160206040518083038186803b158015611fc857600080fd5b505afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906129a8565b6040516001600160e01b031960e085901b1681526004810192909252602482015260016044820152606401602060405180830381600087803b15801561204557600080fd5b505af1158015612059573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207d919061296d565b9050806105d65760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f206465706f73697420746f20436f6e76657800000000006044820152606401610366565b6001600160a01b0381166121225760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610366565b806001600160a01b0316612142600080516020612d898339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611d4281600080516020612d8983398151915255565b609d546040516370a0823160e01b8152306004820152600091829182916001600160a01b0316906370a082319060240160206040518083038186803b1580156121d557600080fd5b505afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d91906129a8565b609f546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a082319060240160206040518083038186803b15801561225157600080fd5b505afa158015612265573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228991906129a8565b91506122958284612b6f565b9050909192565b609f54604051636197390160e11b815260048101839052600160248201526001600160a01b039091169063c32e720290604401600060405180830381600087803b1580156122e957600080fd5b505af11580156122fd573d6000803e3d6000fd5b5050505050565b6033548190612321906001600160a01b0380841691166000612418565b6033546105d6906001600160a01b038381169116600019612418565b6000612392826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166125769092919063ffffffff16565b805190915015611a7d57808060200190518101906123b0919061296d565b611a7d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610366565b6105d682612304565b8015806124a15750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561246757600080fd5b505afa15801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f91906129a8565b155b61250c5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610366565b6040516001600160a01b038316602482015260448101829052611a7d90849063095ea7b360e01b90606401611a46565b6000611f2d8284612c94565b6000611f2d8284612b87565b600080612561858561253c565b905061256d8184612548565b95945050505050565b6060611f55848460008585843b6125cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610366565b600080866001600160a01b031685876040516125eb9190612a0d565b60006040518083038185875af1925050503d8060008114612628576040519150601f19603f3d011682016040523d82523d6000602084013e61262d565b606091505b509150915061263d828286612648565b979650505050505050565b60608315612657575081611f2d565b8251156126675782518084602001fd5b8160405162461bcd60e51b81526004016103669190612a44565b60405180606001604052806003906020820280368337509192915050565b80356126aa81612d53565b919050565b60008083601f8401126126c157600080fd5b50813567ffffffffffffffff8111156126d957600080fd5b6020830191508360208260051b85010111156126f457600080fd5b9250929050565b60006020828403121561270d57600080fd5b8135611f2d81612d53565b60006020828403121561272a57600080fd5b8151611f2d81612d53565b6000806040838503121561274857600080fd5b823561275381612d53565b9150602083013561276381612d53565b809150509250929050565b60008060008060008060008060008060006101208c8e03121561279057600080fd5b61279a8c35612d53565b8b359a506127ab60208d0135612d53565b60208c013599506127be60408d0161269f565b98506127cc60608d0161269f565b975067ffffffffffffffff8060808e013511156127e857600080fd5b6127f88e60808f01358f016126af565b909850965060a08d013581101561280e57600080fd5b5061281f8d60a08e01358e016126af565b909550935061283060c08d0161269f565b925061283e60e08d0161269f565b91506101008c013590509295989b509295989b9093969950565b600080600080600080600060a0888a03121561287357600080fd5b873561287e81612d53565b9650602088013561288e81612d53565b9550604088013561289e81612d53565b9450606088013567ffffffffffffffff808211156128bb57600080fd5b6128c78b838c016126af565b909650945060808a01359150808211156128e057600080fd5b506128ed8a828b016126af565b989b979a50959850939692959293505050565b60008060006060848603121561291557600080fd5b833561292081612d53565b9250602084013561293081612d53565b929592945050506040919091013590565b6000806040838503121561295457600080fd5b823561295f81612d53565b946020939093013593505050565b60006020828403121561297f57600080fd5b81518015158114611f2d57600080fd5b6000602082840312156129a157600080fd5b5035919050565b6000602082840312156129ba57600080fd5b5051919050565b6000602082840312156129d357600080fd5b815160ff81168114611f2d57600080fd5b8060005b6003811015612a075781518452602093840193909101906001016129e8565b50505050565b60008251612a1f818460208701612cca565b9190910192915050565b60808101612a3782856129e4565b8260608301529392505050565b6020815260008251806020840152612a63816040850160208701612cca565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b82815260808101611f2d60208301846129e4565b60008219821115612b8257612b82612d11565b500190565b600082612ba457634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612be4578160001904821115612bca57612bca612d11565b80851615612bd757918102915b93841c9390800290612bae565b509250929050565b6000611f2d8383600082612c0257506001611eca565b81612c0f57506000611eca565b8160018114612c255760028114612c2f57612c4b565b6001915050611eca565b60ff841115612c4057612c40612d11565b50506001821b611eca565b5060208310610133831016604e8410600b8410161715612c6e575081810a611eca565b612c788383612ba9565b8060001904821115612c8c57612c8c612d11565b029392505050565b6000816000190483118215151615612cae57612cae612d11565b500290565b600082821015612cc557612cc5612d11565b500390565b60005b83811015612ce5578181015183820152602001612ccd565b83811115612a075750506000910152565b6000600019821415612d0a57612d0a612d11565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114611d4257600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220e3238969a2d8ae5ccdfe5ad9a29407b821c3f5f49c48082df126d6e25f86062264736f6c63430008070033", + "solcInputHash": "a9ed004f4d203a17c07bb1c3b7c6c7b7", + "metadata": "{\"compiler\":{\"version\":\"0.8.7+commit.e28d00a7\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_oldAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newAddress\",\"type\":\"address\"}],\"name\":\"CvxRewardTokenAddressUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"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\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"PTokenRemoved\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"_oldThreshold\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newThreshold\",\"type\":\"uint256\"}],\"name\":\"RewardLiquidationThresholdUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_oldAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newAddress\",\"type\":\"address\"}],\"name\":\"RewardTokenAddressUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardTokenCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"assetToPToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"checkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collectRewardToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cvxRewardTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vaultAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_cvxRewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"_cvxDepositorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_cvxRewardStakerAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cvxDepositorPTokenId\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_platformAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vaultAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"_assets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_pTokens\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isGovernor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"platformAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_assetIndex\",\"type\":\"uint256\"}],\"name\":\"removePToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardLiquidationThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safeApproveAllTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_cvxRewardTokenAddress\",\"type\":\"address\"}],\"name\":\"setCvxRewardTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_pToken\",\"type\":\"address\"}],\"name\":\"setPTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"name\":\"setRewardLiquidationThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rewardTokenAddress\",\"type\":\"address\"}],\"name\":\"setRewardTokenAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"}],\"name\":\"supportsAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newGovernor\",\"type\":\"address\"}],\"name\":\"transferGovernance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"transferToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"checkBalance(address)\":{\"details\":\"Get the total asset value held in the platform\",\"params\":{\"_asset\":\"Address of the asset\"},\"returns\":{\"balance\":\" Total value of the asset in the platform\"}},\"claimGovernance()\":{\"details\":\"Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor.\"},\"collectRewardToken()\":{\"details\":\"Collect accumulated CRV and CVX and send to Vault.\"},\"deposit(address,uint256)\":{\"details\":\"Deposit asset into the Curve 3Pool\",\"params\":{\"_amount\":\"Amount of asset to deposit\",\"_asset\":\"Address of asset to deposit\"}},\"depositAll()\":{\"details\":\"Deposit the entire balance of any supported asset into the Curve 3pool\"},\"governor()\":{\"details\":\"Returns the address of the current Governor.\"},\"initialize(address,address,address,address,address[],address[],address,address,uint256)\":{\"params\":{\"_assets\":\"Addresses of supported assets. MUST be passed in the same order as returned by coins on the pool contract, i.e. DAI, USDC, USDT\",\"_cvxDepositorAddress\":\"Address of the Convex depositor(AKA booster) for this pool\",\"_cvxDepositorPTokenId\":\"Pid of the pool referred to by Depositor and staker\",\"_cvxRewardStakerAddress\":\"Address of the CVX rewards staker\",\"_cvxRewardTokenAddress\":\"Address of CVX *yes we get both*\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_platformAddress\":\"Address of the Curve 3pool\",\"_rewardTokenAddress\":\"Address of CRV\",\"_vaultAddress\":\"Address of the vault\"}},\"initialize(address,address,address,address[],address[])\":{\"details\":\"Internal initialize function, to set up initial internal state\",\"params\":{\"_assets\":\"Addresses of initial supported assets\",\"_pTokens\":\"Platform Token corresponding addresses\",\"_platformAddress\":\"Generic platform address\",\"_rewardTokenAddress\":\"Address of reward token for platform\",\"_vaultAddress\":\"Address of the Vault\"}},\"isGovernor()\":{\"details\":\"Returns true if the caller is the current Governor.\"},\"removePToken(uint256)\":{\"details\":\"Remove a supported asset by passing its index. This method can only be called by the system Governor\",\"params\":{\"_assetIndex\":\"Index of the asset to be removed\"}},\"safeApproveAllTokens()\":{\"details\":\"Approve the spending of all assets by their corresponding pool tokens, if for some reason is it necessary.\"},\"setCvxRewardTokenAddress(address)\":{\"details\":\"Set the CVX reward token address.\",\"params\":{\"_cvxRewardTokenAddress\":\"Address of the reward token\"}},\"setPTokenAddress(address,address)\":{\"details\":\"Provide support for asset by passing its pToken address. This method can only be called by the system Governor\",\"params\":{\"_asset\":\"Address for the asset\",\"_pToken\":\"Address for the corresponding platform token\"}},\"setRewardLiquidationThreshold(uint256)\":{\"details\":\"Set the reward token liquidation threshold.\",\"params\":{\"_threshold\":\"Threshold amount in decimals of reward token that will cause the Vault to claim and withdrawAll on allocate() calls.\"}},\"setRewardTokenAddress(address)\":{\"details\":\"Set the reward token address.\",\"params\":{\"_rewardTokenAddress\":\"Address of the reward token\"}},\"supportsAsset(address)\":{\"details\":\"Retuns bool indicating whether asset is supported by strategy\",\"params\":{\"_asset\":\"Address of the asset\"}},\"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\"}},\"transferToken(address,uint256)\":{\"details\":\"Transfer token to governor. Intended for recovering tokens stuck in strategy contracts, i.e. mistaken sends.\",\"params\":{\"_amount\":\"Amount of the asset to transfer\",\"_asset\":\"Address for the asset\"}},\"withdraw(address,address,uint256)\":{\"details\":\"Withdraw asset from Curve 3Pool\",\"params\":{\"_amount\":\"Amount of asset to withdraw\",\"_asset\":\"Address of asset to withdraw\",\"_recipient\":\"Address to receive withdrawn asset\"}},\"withdrawAll()\":{\"details\":\"Remove all assets from platform and send them to Vault contract.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"initialize(address,address,address,address,address[],address[],address,address,uint256)\":{\"notice\":\"Initializer for setting up strategy internal state. This overrides the InitializableAbstractStrategy initializer as Curve strategies don't fit well within that abstraction.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/ConvexStrategy.sol\":\"ConvexStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\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(\\n address sender,\\n address recipient,\\n uint256 amount\\n ) 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\":\"0x027b891937d20ccf213fdb9c31531574256de774bda99d3a70ecef6e1913ed2a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.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 IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\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. We use {Address.functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x02348b2e4b9f3200c7e3907c5c2661643a6d8520e9f79939fbb9b4005a54894d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\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 // This method relies on extcodesize, which returns 0 for contracts in\\n // construction, since the code is only stored at the end of the\\n // constructor execution.\\n\\n uint256 size;\\n assembly {\\n size := extcodesize(account)\\n }\\n return size > 0;\\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 function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3336baae5cf23e94274d75336e2d412193be508504aee185e61dc7d58cd05c8a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\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) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\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 *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\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 *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\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 *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting 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 *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\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 * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting 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 *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\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 *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8666f020bd8fc9dc14f07e2ebc52b5f236ab4cdde7c77679b08cb2f94730043b\",\"license\":\"MIT\"},\"contracts/governance/Governable.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\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 private constant governorPosition =\\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\\n\\n // keccak256(\\\"OUSD.pending.governor\\\");\\n bytes32 private constant pendingGovernorPosition =\\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\\n\\n // keccak256(\\\"OUSD.reentry.status\\\");\\n bytes32 private constant reentryStatusPosition =\\n 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() {\\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\":\"0x29d258134253bdaeeea64c17baaf6108ff50aec65ceddb7216ef3a948a88808c\",\"license\":\"agpl-3.0\"},\"contracts/interfaces/IBasicToken.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IBasicToken {\\n function symbol() external view returns (string memory);\\n\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0xcabd808c03076fa6fb5838a13210b2b99314d23842e0e3d5e55e0c1466e75212\",\"license\":\"agpl-3.0\"},\"contracts/strategies/BaseCurveStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Curve 3Pool Strategy\\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\\n * @author Origin Protocol Inc\\n */\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { ICurvePool } from \\\"./ICurvePool.sol\\\";\\nimport { ICRVMinter } from \\\"./ICRVMinter.sol\\\";\\nimport { IERC20, InitializableAbstractStrategy } from \\\"../utils/InitializableAbstractStrategy.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Helpers } from \\\"../utils/Helpers.sol\\\";\\n\\nabstract contract BaseCurveStrategy is InitializableAbstractStrategy {\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n uint256 internal constant maxSlippage = 1e16; // 1%, same as the Curve UI\\n address internal pTokenAddress;\\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 override\\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 uint256 poolCoinIndex = _getCoinIndex(_asset);\\n // Set the amount on the asset we want to deposit\\n _amounts[poolCoinIndex] = _amount;\\n ICurvePool curvePool = ICurvePool(platformAddress);\\n uint256 assetDecimals = Helpers.getDecimals(_asset);\\n uint256 depositValue = _amount.scaleBy(18, assetDecimals).divPrecisely(\\n curvePool.get_virtual_price()\\n );\\n uint256 minMintAmount = depositValue.mulTruncate(\\n uint256(1e18) - maxSlippage\\n );\\n // Do the deposit to 3pool\\n curvePool.add_liquidity(_amounts, minMintAmount);\\n _lpDepositAll();\\n }\\n\\n function _lpDepositAll() internal virtual;\\n\\n /**\\n * @dev Deposit the entire balance of any supported asset into the Curve 3pool\\n */\\n function depositAll() external override onlyVault nonReentrant {\\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\\n uint256 depositValue = 0;\\n ICurvePool curvePool = ICurvePool(platformAddress);\\n uint256 curveVirtualPrice = curvePool.get_virtual_price();\\n\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n address assetAddress = assetsMapped[i];\\n uint256 balance = IERC20(assetAddress).balanceOf(address(this));\\n if (balance > 0) {\\n uint256 poolCoinIndex = _getCoinIndex(assetAddress);\\n // Set the amount on the asset we want to deposit\\n _amounts[poolCoinIndex] = balance;\\n uint256 assetDecimals = Helpers.getDecimals(assetAddress);\\n // Get value of deposit in Curve LP token to later determine\\n // the minMintAmount argument for add_liquidity\\n depositValue =\\n depositValue +\\n balance.scaleBy(18, assetDecimals).divPrecisely(\\n curveVirtualPrice\\n );\\n emit Deposit(assetAddress, address(platformAddress), balance);\\n }\\n }\\n\\n uint256 minMintAmount = depositValue.mulTruncate(\\n uint256(1e18) - maxSlippage\\n );\\n // Do the deposit to 3pool\\n curvePool.add_liquidity(_amounts, minMintAmount);\\n // Deposit into Gauge, the PToken is the same (3Crv) for all mapped\\n // assets, so just get the address from the first one\\n _lpDepositAll();\\n }\\n\\n function _lpWithdraw(uint256 numPTokens) internal virtual;\\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 override onlyVault nonReentrant {\\n require(_amount > 0, \\\"Invalid amount\\\");\\n\\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\\n\\n (uint256 contractPTokens, , uint256 totalPTokens) = _getTotalPTokens();\\n\\n uint256 coinIndex = _getCoinIndex(_asset);\\n int128 curveCoinIndex = int128(uint128(coinIndex));\\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 // Calculate how many platform tokens we need to withdraw the asset\\n // amount in the worst case (i.e withdrawing all LP tokens)\\n uint256 maxAmount = curvePool.calc_withdraw_one_coin(\\n totalPTokens,\\n curveCoinIndex\\n );\\n uint256 maxBurnedPTokens = (totalPTokens * _amount) / maxAmount;\\n\\n // Not enough in this contract or in the Gauge, can't proceed\\n require(totalPTokens > maxBurnedPTokens, \\\"Insufficient 3CRV balance\\\");\\n // We have enough LP tokens, make sure they are all on this contract\\n if (contractPTokens < maxBurnedPTokens) {\\n _lpWithdraw(maxBurnedPTokens - contractPTokens);\\n }\\n\\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\\n _amounts[coinIndex] = _amount;\\n curvePool.remove_liquidity_imbalance(_amounts, maxBurnedPTokens);\\n\\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 override onlyVaultOrGovernor nonReentrant {\\n // Withdraw all from Gauge\\n (, uint256 gaugePTokens, uint256 totalPTokens) = _getTotalPTokens();\\n _lpWithdraw(gaugePTokens);\\n // Withdraws are proportional to assets held by 3Pool\\n uint256[3] memory minWithdrawAmounts = [\\n uint256(0),\\n uint256(0),\\n uint256(0)\\n ];\\n // Remove liquidity\\n ICurvePool threePool = ICurvePool(platformAddress);\\n threePool.remove_liquidity(totalPTokens, minWithdrawAmounts);\\n // Transfer assets out of Vault\\n // Note that Curve will provide all 3 of the assets in 3pool even if\\n // we have not set PToken addresses for all of them in this strategy\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n IERC20 asset = IERC20(threePool.coins(i));\\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\\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 public\\n view\\n override\\n returns (uint256 balance)\\n {\\n require(assetToPToken[_asset] != address(0), \\\"Unsupported asset\\\");\\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 ICurvePool curvePool = ICurvePool(platformAddress);\\n if (totalPTokens > 0) {\\n uint256 virtual_price = curvePool.get_virtual_price();\\n uint256 value = (totalPTokens * virtual_price) / 1e18;\\n uint256 assetDecimals = Helpers.getDecimals(_asset);\\n balance = value.scaleBy(assetDecimals, 18) / 3;\\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)\\n external\\n view\\n override\\n returns (bool)\\n {\\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()\\n external\\n override\\n onlyGovernor\\n nonReentrant\\n {\\n _approveBase();\\n // This strategy is a special case since it only supports one asset\\n for (uint256 i = 0; i < assetsMapped.length; i++) {\\n _approveAsset(assetsMapped[i]);\\n }\\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 contractPTokens Amount of platform tokens in this contract\\n * @return gaugePTokens Amount of platform tokens staked in gauge\\n * @return totalPTokens Total amount of platform tokens in native decimals\\n */\\n function _getTotalPTokens()\\n internal\\n view\\n virtual\\n returns (\\n uint256 contractPTokens,\\n uint256 gaugePTokens,\\n uint256 totalPTokens\\n );\\n\\n /**\\n * @dev Call the necessary approvals for the Curve pool and gauge\\n * @param _asset Address of the asset\\n */\\n function _abstractSetPToken(address _asset, address _pToken)\\n internal\\n override\\n {\\n _approveAsset(_asset);\\n }\\n\\n function _approveAsset(address _asset) internal {\\n IERC20 asset = IERC20(_asset);\\n // 3Pool for asset (required for adding liquidity)\\n asset.safeApprove(platformAddress, 0);\\n asset.safeApprove(platformAddress, type(uint256).max);\\n }\\n\\n function _approveBase() internal virtual;\\n\\n /**\\n * @dev Get the index of the coin\\n */\\n function _getCoinIndex(address _asset) internal view returns (uint256) {\\n for (uint256 i = 0; i < 3; i++) {\\n if (assetsMapped[i] == _asset) return i;\\n }\\n revert(\\\"Invalid 3pool asset\\\");\\n }\\n}\\n\",\"keccak256\":\"0x8aa30fd3b68bd495470a73a44c50736563507a4d49c20c6a7eadafd9708e5391\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ConvexStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Curve Convex Strategy\\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\\n * @author Origin Protocol Inc\\n */\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\nimport { IRewardStaking } from \\\"./IRewardStaking.sol\\\";\\nimport { IConvexDeposits } from \\\"./IConvexDeposits.sol\\\";\\nimport { IERC20, BaseCurveStrategy } from \\\"./BaseCurveStrategy.sol\\\";\\nimport { StableMath } from \\\"../utils/StableMath.sol\\\";\\nimport { Helpers } from \\\"../utils/Helpers.sol\\\";\\n\\ncontract ConvexStrategy is BaseCurveStrategy {\\n using StableMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n event RewardTokenCollected(\\n address recipient,\\n address token,\\n uint256 amount\\n );\\n\\n event CvxRewardTokenAddressUpdated(\\n address _oldAddress,\\n address _newAddress\\n );\\n\\n address internal cvxDepositorAddress;\\n address internal cvxRewardStakerAddress;\\n address public cvxRewardTokenAddress;\\n uint256 internal cvxDepositorPTokenId;\\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 _cvxRewardTokenAddress Address of CVX *yes we get both*\\n * @param _assets Addresses of supported assets. MUST be passed in the same\\n * order as returned by coins on the pool contract, i.e.\\n * DAI, USDC, USDT\\n * @param _pTokens Platform Token corresponding addresses\\n * @param _cvxDepositorAddress Address of the Convex depositor(AKA booster) for this pool\\n * @param _cvxRewardStakerAddress Address of the CVX rewards staker\\n * @param _cvxDepositorPTokenId Pid of the pool referred to by Depositor and staker\\n */\\n function initialize(\\n address _platformAddress, // 3Pool address\\n address _vaultAddress,\\n address _rewardTokenAddress, // CRV\\n address _cvxRewardTokenAddress, // CVX\\n address[] calldata _assets,\\n address[] calldata _pTokens,\\n address _cvxDepositorAddress,\\n address _cvxRewardStakerAddress,\\n uint256 _cvxDepositorPTokenId\\n ) external onlyGovernor initializer {\\n require(_assets.length == 3, \\\"Must have exactly three assets\\\");\\n // Should be set prior to abstract initialize call otherwise\\n // abstractSetPToken calls will fail\\n cvxDepositorAddress = _cvxDepositorAddress;\\n cvxRewardStakerAddress = _cvxRewardStakerAddress;\\n cvxDepositorPTokenId = _cvxDepositorPTokenId;\\n cvxRewardTokenAddress = _cvxRewardTokenAddress;\\n pTokenAddress = _pTokens[0];\\n super._initialize(\\n _platformAddress,\\n _vaultAddress,\\n _rewardTokenAddress,\\n _assets,\\n _pTokens\\n );\\n _approveBase();\\n }\\n\\n /**\\n * @dev Set the CVX reward token address.\\n * @param _cvxRewardTokenAddress Address of the reward token\\n */\\n function setCvxRewardTokenAddress(address _cvxRewardTokenAddress)\\n external\\n onlyGovernor\\n {\\n emit CvxRewardTokenAddressUpdated(\\n cvxRewardTokenAddress,\\n _cvxRewardTokenAddress\\n );\\n cvxRewardTokenAddress = _cvxRewardTokenAddress;\\n }\\n\\n function _lpDepositAll() internal override {\\n IERC20 pToken = IERC20(pTokenAddress);\\n // Deposit with staking\\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\\n cvxDepositorPTokenId,\\n pToken.balanceOf(address(this)),\\n true\\n );\\n require(success, \\\"Failed to deposit to Convex\\\");\\n }\\n\\n function _lpWithdraw(uint256 numPTokens) internal override {\\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\\n numPTokens,\\n true\\n );\\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 contractPTokens Amount of platform tokens in this contract\\n * @return gaugePTokens Amount of platform tokens staked in gauge\\n * @return totalPTokens Total amount of platform tokens in native decimals\\n */\\n function _getTotalPTokens()\\n internal\\n view\\n override\\n returns (\\n uint256 contractPTokens,\\n uint256 gaugePTokens, // gauge is a misnomer here, need a better name\\n uint256 totalPTokens\\n )\\n {\\n contractPTokens = IERC20(pTokenAddress).balanceOf(address(this));\\n gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\\n address(this)\\n ); //booster.poolInfo[pid].token.balanceOf(address(this)) Not needed if we always stake..\\n totalPTokens = contractPTokens + gaugePTokens;\\n }\\n\\n function _approveBase() internal override {\\n IERC20 pToken = IERC20(pTokenAddress);\\n // 3Pool for LP token (required for removing liquidity)\\n pToken.safeApprove(platformAddress, 0);\\n pToken.safeApprove(platformAddress, type(uint256).max);\\n // Gauge for LP token\\n pToken.safeApprove(cvxDepositorAddress, 0);\\n pToken.safeApprove(cvxDepositorAddress, type(uint256).max);\\n }\\n\\n /**\\n * @dev Collect accumulated CRV and CVX and send to Vault.\\n */\\n function collectRewardToken() external override onlyVault nonReentrant {\\n // Collect CRV and CVX\\n IRewardStaking(cvxRewardStakerAddress).getReward();\\n // Send CRV\\n IERC20 crvToken = IERC20(rewardTokenAddress);\\n uint256 balance = crvToken.balanceOf(address(this));\\n emit RewardTokenCollected(vaultAddress, rewardTokenAddress, balance);\\n crvToken.safeTransfer(vaultAddress, balance);\\n // Send CVX\\n IERC20 cvxToken = IERC20(cvxRewardTokenAddress);\\n balance = cvxToken.balanceOf(address(this));\\n emit RewardTokenCollected(vaultAddress, cvxRewardTokenAddress, balance);\\n cvxToken.safeTransfer(vaultAddress, balance);\\n }\\n}\\n\",\"keccak256\":\"0xaecd4df3835c8a452b4e4f7c679708d514237f8a56929f3f09b21a35049c9683\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ICRVMinter.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface ICRVMinter {\\n function mint(address gaugeAddress) external;\\n}\\n\",\"keccak256\":\"0x2b688e8ee9b61faeaf9362bb3d5f21f622fc1a2c2eec81badde983e9a34b16c5\",\"license\":\"agpl-3.0\"},\"contracts/strategies/IConvexDeposits.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IConvexDeposits {\\n function deposit(\\n uint256 _pid,\\n uint256 _amount,\\n bool _stake\\n ) external returns (bool);\\n\\n function deposit(\\n uint256 _amount,\\n bool _lock,\\n address _stakeAddress\\n ) external;\\n}\\n\",\"keccak256\":\"0xaeb8e3858c2678e4e915c4f8f30d07941de7bc62139513f4443a041c3f224364\",\"license\":\"agpl-3.0\"},\"contracts/strategies/ICurvePool.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface ICurvePool {\\n function get_virtual_price() external view returns (uint256);\\n\\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\\n\\n function balances(uint256) external view returns (uint256);\\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 remove_liquidity(\\n uint256 _amount,\\n uint256[3] calldata _minWithdrawAmounts\\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 function remove_liquidity_imbalance(\\n uint256[3] calldata _amounts,\\n uint256 maxBurnAmount\\n ) external;\\n}\\n\",\"keccak256\":\"0xd1faec85f8e7c5b29526b14770e9f4e7b29a542a7378c9b58574280b7bd94131\",\"license\":\"agpl-3.0\"},\"contracts/strategies/IRewardStaking.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\ninterface IRewardStaking {\\n function stakeFor(address, uint256) external;\\n\\n function stake(uint256) external;\\n\\n function withdraw(uint256 amount, bool claim) external;\\n\\n function withdrawAndUnwrap(uint256 amount, bool claim) external;\\n\\n function earned(address account) external view returns (uint256);\\n\\n function getReward() external;\\n\\n function getReward(address _account, bool _claimExtras) external;\\n\\n function extraRewardsLength() external returns (uint256);\\n\\n function extraRewards(uint256 _pid) external returns (address);\\n\\n function rewardToken() external returns (address);\\n\\n function balanceOf(address account) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x06ca761842121009d3fe326fd61d3108fdad0ac2c95b94b723a322228578d8b2\",\"license\":\"agpl-3.0\"},\"contracts/utils/Helpers.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\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\",\"keccak256\":\"0x7ce41c7eacd2b6722029bd87759fe6e4d9b48a862277707737be82c94581b855\",\"license\":\"agpl-3.0\"},\"contracts/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nabstract contract Initializable {\\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 protect an initializer function from being invoked twice.\\n */\\n modifier initializer() {\\n require(\\n initializing || !initialized,\\n \\\"Initializable: contract is already initialized\\\"\\n );\\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 uint256[50] private ______gap;\\n}\\n\",\"keccak256\":\"0xff2a83835ed8984e10338905bc31dbcaeeabdfc0e58d49257389cb1e5a3b9d8a\",\"license\":\"agpl-3.0\"},\"contracts/utils/InitializableAbstractStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\nimport { Initializable } from \\\"../utils/Initializable.sol\\\";\\nimport { Governable } from \\\"../governance/Governable.sol\\\";\\n\\nabstract contract 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 event RewardTokenAddressUpdated(address _oldAddress, address _newAddress);\\n event RewardLiquidationThresholdUpdated(\\n uint256 _oldThreshold,\\n uint256 _newThreshold\\n );\\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 // Reserved for future expansion\\n int256[100] private _reserved;\\n\\n /**\\n * @dev Internal initialize function, to set up initial internal state\\n * @param _platformAddress Generic 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 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 Collect accumulated reward token and send to Vault.\\n */\\n function collectRewardToken() external virtual 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 /**\\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 emit RewardTokenAddressUpdated(rewardTokenAddress, _rewardTokenAddress);\\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 emit RewardLiquidationThresholdUpdated(\\n rewardLiquidationThreshold,\\n _threshold\\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)\\n internal\\n virtual;\\n\\n function safeApproveAllTokens() external virtual;\\n\\n /**\\n * @dev Deposit an 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 virtual;\\n\\n /**\\n * @dev Deposit balance of all supported assets into the platform\\n */\\n function depositAll() external virtual;\\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 virtual;\\n\\n /**\\n * @dev Withdraw all assets from strategy sending assets to Vault.\\n */\\n function withdrawAll() external virtual;\\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 virtual\\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 virtual returns (bool);\\n}\\n\",\"keccak256\":\"0xa8716794f09bca7859cb8bcc9c8e01acd73f326682e34cf3471fd9984fd30d18\",\"license\":\"agpl-3.0\"},\"contracts/utils/StableMath.sol\":{\"content\":\"// SPDX-License-Identifier: agpl-3.0\\npragma solidity ^0.8.0;\\n\\nimport { SafeMath } from \\\"@openzeppelin/contracts/utils/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 to Decimals to scale to\\n * @param from Decimals to scale from\\n */\\n function scaleBy(\\n uint256 x,\\n uint256 to,\\n uint256 from\\n ) internal pure returns (uint256) {\\n if (to > from) {\\n x = x.mul(10**(to - from));\\n } else if (to < from) {\\n x = x.div(10**(from - to));\\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 9e36 / 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\":\"0x3dd9c475e374285f00f73351de859ed44b490f9989baee63c2d5db79b41aa9e8\",\"license\":\"agpl-3.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506100283360008051602062002faf83398151915255565b60008051602062002faf833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a3612f2f80620000806000396000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c8063790fcf9f116100de578063c7af335211610097578063d7dc031211610071578063d7dc031214610357578063d9caed121461036a578063dbe55e561461037d578063de5f62681461039057600080fd5b8063c7af335214610329578063cd3b021214610331578063d38bfff41461034457600080fd5b8063790fcf9f146102a2578063853828b6146102b55780639136616a146102bd5780639a6acf20146102d0578063aa388af6146102e3578063ad1728cb1461032157600080fd5b80631a89a4d41161014b57806347e7ef241161012557806347e7ef241461025d5780635653b414146102705780635d36b190146102875780635f5152261461028f57600080fd5b80631a89a4d41461022457806327e5140f14610237578063430bf08a1461024a57600080fd5b80630242241d146101935780630c340a241461019d5780630ed57b3a146101c25780630fc3b4c4146101d55780631072cbea146101fe578063125f9e3314610211575b600080fd5b61019b610398565b005b6101a561064f565b6040516001600160a01b0390911681526020015b60405180910390f35b61019b6101d0366004612886565b61066c565b6101a56101e336600461284c565b6035602052600090815260409020546001600160a01b031681565b61019b61020c366004612a92565b61069e565b6037546101a5906001600160a01b031681565b61019b6102323660046128bf565b6106de565b61019b61024536600461284c565b6108cf565b6034546101a5906001600160a01b031681565b61019b61026b366004612a92565b61095c565b61027960385481565b6040519081526020016101b9565b61019b610bbf565b61027961029d36600461284c565b610c65565b61019b6102b03660046129a9565b610dac565b61019b610eb3565b61019b6102cb366004612ae0565b611148565b61019b6102de36600461284c565b611313565b6103116102f136600461284c565b6001600160a01b0390811660009081526035602052604090205416151590565b60405190151581526020016101b9565b61019b6113a0565b610311611459565b61019b61033f366004612ae0565b61148a565b61019b61035236600461284c565b6114ef565b60a0546101a5906001600160a01b031681565b61019b610378366004612a51565b611593565b6033546101a5906001600160a01b031681565b61019b61187b565b6034546001600160a01b031633146103cb5760405162461bcd60e51b81526004016103c290612bc8565b60405180910390fd5b600080516020612eba833981519152805460028114156103fd5760405162461bcd60e51b81526004016103c290612c84565b60028255609f60009054906101000a90046001600160a01b03166001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561045157600080fd5b505af1158015610465573d6000803e3d6000fd5b50506037546040516370a0823160e01b81523060048201526001600160a01b0390911692506000915082906370a082319060240160206040518083038186803b1580156104b157600080fd5b505afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e99190612af9565b603454603754604080516001600160a01b03938416815292909116602083015281018290529091507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610558906001600160a01b03848116911683611b6b565b60a0546040516370a0823160e01b81523060048201526001600160a01b039091169081906370a082319060240160206040518083038186803b15801561059d57600080fd5b505afa1580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190612af9565b60345460a054604080516001600160a01b03938416815292909116602083015281018290529092507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610644906001600160a01b03838116911684611b6b565b505050600182555050565b6000610667600080516020612eda8339815191525490565b905090565b610674611459565b6106905760405162461bcd60e51b81526004016103c290612bff565b61069a8282611bd3565b5050565b6106a6611459565b6106c25760405162461bcd60e51b81526004016103c290612bff565b61069a6106cd61064f565b6001600160a01b0384169083611b6b565b6106e6611459565b6107025760405162461bcd60e51b81526004016103c290612bff565b600054610100900460ff168061071b575060005460ff16155b6107375760405162461bcd60e51b81526004016103c290612c36565b600054610100900460ff16158015610759576000805461ffff19166101011790555b600387146107a95760405162461bcd60e51b815260206004820152601e60248201527f4d75737420686176652065786163746c7920746872656520617373657473000060448201526064016103c2565b609e80546001600160a01b038087166001600160a01b031992831617909255609f805486841690831617905560a184905560a08054928c169290911691909117905585856000816107fc576107fc612e8e565b9050602002016020810190610811919061284c565b609d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055506108a78c8c8c8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d918291850190849080828437600092019190915250611d3892505050565b6108af611e20565b80156108c1576000805461ff00191690555b505050505050505050505050565b6108d7611459565b6108f35760405162461bcd60e51b81526004016103c290612bff565b60a054604080516001600160a01b03928316815291831660208301527f144d9f91f22eaef5ccf23cd53ea617c4c518097dd96a5176910746f825d0a5b8910160405180910390a160a080546001600160a01b0319166001600160a01b0392909216919091179055565b6034546001600160a01b031633146109865760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156109b85760405162461bcd60e51b81526004016103c290612c84565b6002825560008311610a055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b60448201526064016103c2565b603354604080516001600160a01b03928316815260208101869052918616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a2610a576127d2565b6000610a6286611e96565b905084828260038110610a7757610a77612e8e565b60200201526033546001600160a01b03166000610a9388611f32565b90506000610b1d836001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad357600080fd5b505afa158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b9190612af9565b610b178a601286612021565b90612085565b90506000610b44610b3d662386f26fc10000670de0b6b3a7640000612e04565b83906120ae565b604051634515cef360e01b81529091506001600160a01b03851690634515cef390610b759089908590600401612b7a565b600060405180830381600087803b158015610b8f57600080fd5b505af1158015610ba3573d6000803e3d6000fd5b50505050610baf6120c3565b5050505050506001825550505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610c5a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016103c2565b610c633361221d565b565b6001600160a01b03818116600090815260356020526040812054909116610cc25760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b60448201526064016103c2565b6000610ccc6122de565b6033549093506001600160a01b03169150508115610da5576000816001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610d1f57600080fd5b505afa158015610d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d579190612af9565b90506000670de0b6b3a7640000610d6e8386612de5565b610d789190612cd8565b90506000610d8587611f32565b90506003610d9583836012612021565b610d9f9190612cd8565b95505050505b5050919050565b610db4611459565b610dd05760405162461bcd60e51b81526004016103c290612bff565b600054610100900460ff1680610de9575060005460ff16155b610e055760405162461bcd60e51b81526004016103c290612c36565b600054610100900460ff16158015610e27576000805461ffff19166101011790555b610e9788888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611d3892505050565b8015610ea9576000805461ff00191690555b5050505050505050565b6034546001600160a01b0316331480610ee45750610ecf61064f565b6001600160a01b0316336001600160a01b0316145b610f3c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b60648201526084016103c2565b600080516020612eba83398151915280546002811415610f6e5760405162461bcd60e51b81526004016103c290612c84565b60028255600080610f7d6122de565b9250925050610f8b826123ed565b6040805160608101825260008082526020820181905281830152603354915163ecb586a560e01b815290916001600160a01b031690819063ecb586a590610fd89086908690600401612cac565b600060405180830381600087803b158015610ff257600080fd5b505af1158015611006573d6000803e3d6000fd5b5050505060005b60365481101561113b5760405163c661065760e01b8152600481018290526000906001600160a01b0384169063c66106579060240160206040518083038186803b15801561105a57600080fd5b505afa15801561106e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110929190612869565b6034546040516370a0823160e01b8152306004820152919250611128916001600160a01b03918216918416906370a082319060240160206040518083038186803b1580156110df57600080fd5b505afa1580156110f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111179190612af9565b6001600160a01b0384169190611b6b565b508061113381612e47565b91505061100d565b5050505050600182555050565b611150611459565b61116c5760405162461bcd60e51b81526004016103c290612bff565b60365481106111ad5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016103c2565b6000603682815481106111c2576111c2612e8e565b60009182526020808320909101546001600160a01b039081168084526035909252604090922054603654919350909116906111ff90600190612e04565b831015611281576036805461121690600190612e04565b8154811061122657611226612e8e565b600091825260209091200154603680546001600160a01b03909216918590811061125257611252612e8e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b603680548061129257611292612e78565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526035855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61131b611459565b6113375760405162461bcd60e51b81526004016103c290612bff565b603754604080516001600160a01b03928316815291831660208301527f6000690cf6fd1e69830cc1142bc52655402f4a58db681849f61c3c8fb322ff8a910160405180910390a1603780546001600160a01b0319166001600160a01b0392909216919091179055565b6113a8611459565b6113c45760405162461bcd60e51b81526004016103c290612bff565b600080516020612eba833981519152805460028114156113f65760405162461bcd60e51b81526004016103c290612c84565b60028255611402611e20565b60005b6036548110156114515761143f6036828154811061142557611425612e8e565b6000918252602090912001546001600160a01b0316612455565b8061144981612e47565b915050611405565b505060019055565b6000611471600080516020612eda8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611492611459565b6114ae5760405162461bcd60e51b81526004016103c290612bff565b60385460408051918252602082018390527f01538952e8f491e3569a11bf3935ca2fa917ea85ec938dac52e696fbb76d8cc6910160405180910390a1603855565b6114f7611459565b6115135760405162461bcd60e51b81526004016103c290612bff565b61153b817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661155b600080516020612eda8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6034546001600160a01b031633146115bd5760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156115ef5760405162461bcd60e51b81526004016103c290612c84565b60028255600083116116345760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b60448201526064016103c2565b6001600160a01b0384811660008181526035602090815260409182902054825194168452830186905290917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26000806116956122de565b925050915060006116a587611e96565b60335460405163cc2b27d760e01b815260048101859052600f83900b602482015291925082916001600160a01b0390911690600090829063cc2b27d79060440160206040518083038186803b1580156116fd57600080fd5b505afa158015611711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117359190612af9565b90506000816117448b88612de5565b61174e9190612cd8565b905080861161179f5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420334352562062616c616e63650000000000000060448201526064016103c2565b808710156117b9576117b96117b48883612e04565b6123ed565b600060405180606001604052806000815260200160008152602001600081525090508a8187600381106117ee576117ee612e8e565b60200201526040516327f6ba8360e21b81526001600160a01b03851690639fdaea0c906118219084908690600401612b7a565b600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b50611868925050506001600160a01b038d168e8d611b6b565b5050505050505050600182555050505050565b6034546001600160a01b031633146118a55760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156118d75760405162461bcd60e51b81526004016103c290612c84565b6002825560408051606081018252600080825260208083018290528284018290526033548451630176f71760e71b81529451939492936001600160a01b03909116928492849263bb7b8b80926004808201939291829003018186803b15801561193f57600080fd5b505afa158015611953573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119779190612af9565b905060005b603654811015611ada5760006036828154811061199b5761199b612e8e565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156119e957600080fd5b505afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190612af9565b90508015611ac5576000611a3483611e96565b905081888260038110611a4957611a49612e8e565b60200201526000611a5984611f32565b9050611a6b86610b1785601285612021565b611a759089612cc0565b603354604080516001600160a01b03928316815260208101879052929a50908616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a250505b50508080611ad290612e47565b91505061197c565b506000611b00611af9662386f26fc10000670de0b6b3a7640000612e04565b85906120ae565b604051634515cef360e01b81529091506001600160a01b03841690634515cef390611b319088908590600401612b7a565b600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505061113b6120c3565b6040516001600160a01b038316602482015260448101829052611bce90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261248e565b505050565b6001600160a01b038281166000908152603560205260409020541615611c305760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b60448201526064016103c2565b6001600160a01b03821615801590611c5057506001600160a01b03811615155b611c905760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b60448201526064016103c2565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a261069a8282612560565b603380546001600160a01b038088166001600160a01b031992831617909255603480548784169083161790556037805492861692909116919091179055815181518114611dbe5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b60448201526064016103c2565b60005b81811015611e1757611e05848281518110611dde57611dde612e8e565b6020026020010151848381518110611df857611df8612e8e565b6020026020010151611bd3565b80611e0f81612e47565b915050611dc1565b50505050505050565b609d546033546001600160a01b0391821691611e40918391166000612569565b603354611e5c906001600160a01b038381169116600019612569565b609e54611e77906001600160a01b0383811691166000612569565b609e54611e93906001600160a01b038381169116600019612569565b50565b6000805b6003811015611ef357826001600160a01b031660368281548110611ec057611ec0612e8e565b6000918252602090912001546001600160a01b03161415611ee15792915050565b80611eeb81612e47565b915050611e9a565b5060405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59080cdc1bdbdb08185cdcd95d606a1b60448201526064016103c2565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611f6e57600080fd5b505afa158015611f82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa69190612b12565b60ff16905060048110158015611fbd575060128111155b61201b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b60648201526084016103c2565b92915050565b6000818311156120515761204a6120388385612e04565b61204390600a612d3d565b859061268d565b935061207b565b8183101561207b576120786120668484612e04565b61207190600a612d3d565b8590612699565b93505b50825b9392505050565b60008061209a84670de0b6b3a764000061268d565b90506120a68184612699565b949350505050565b600061207e8383670de0b6b3a76400006126a5565b609d54609e5460a1546040516370a0823160e01b81523060048201526001600160a01b039384169360009316916343a0d0669185906370a082319060240160206040518083038186803b15801561211957600080fd5b505afa15801561212d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121519190612af9565b6040516001600160e01b031960e085901b1681526004810192909252602482015260016044820152606401602060405180830381600087803b15801561219657600080fd5b505af11580156121aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ce9190612abe565b90508061069a5760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f206465706f73697420746f20436f6e766578000000000060448201526064016103c2565b6001600160a01b0381166122735760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016103c2565b806001600160a01b0316612293600080516020612eda8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611e9381600080516020612eda83398151915255565b609d546040516370a0823160e01b8152306004820152600091829182916001600160a01b0316906370a082319060240160206040518083038186803b15801561232657600080fd5b505afa15801561233a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235e9190612af9565b609f546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a082319060240160206040518083038186803b1580156123a257600080fd5b505afa1580156123b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123da9190612af9565b91506123e68284612cc0565b9050909192565b609f54604051636197390160e11b815260048101839052600160248201526001600160a01b039091169063c32e720290604401600060405180830381600087803b15801561243a57600080fd5b505af115801561244e573d6000803e3d6000fd5b5050505050565b6033548190612472906001600160a01b0380841691166000612569565b60335461069a906001600160a01b038381169116600019612569565b60006124e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126c79092919063ffffffff16565b805190915015611bce57808060200190518101906125019190612abe565b611bce5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103c2565b61069a82612455565b8015806125f25750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156125b857600080fd5b505afa1580156125cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f09190612af9565b155b61265d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016103c2565b6040516001600160a01b038316602482015260448101829052611bce90849063095ea7b360e01b90606401611b97565b600061207e8284612de5565b600061207e8284612cd8565b6000806126b2858561268d565b90506126be8184612699565b95945050505050565b60606120a6848460008585843b6127205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c2565b600080866001600160a01b0316858760405161273c9190612b5e565b60006040518083038185875af1925050503d8060008114612779576040519150601f19603f3d011682016040523d82523d6000602084013e61277e565b606091505b509150915061278e828286612799565b979650505050505050565b606083156127a857508161207e565b8251156127b85782518084602001fd5b8160405162461bcd60e51b81526004016103c29190612b95565b60405180606001604052806003906020820280368337509192915050565b80356127fb81612ea4565b919050565b60008083601f84011261281257600080fd5b50813567ffffffffffffffff81111561282a57600080fd5b6020830191508360208260051b850101111561284557600080fd5b9250929050565b60006020828403121561285e57600080fd5b813561207e81612ea4565b60006020828403121561287b57600080fd5b815161207e81612ea4565b6000806040838503121561289957600080fd5b82356128a481612ea4565b915060208301356128b481612ea4565b809150509250929050565b60008060008060008060008060008060006101208c8e0312156128e157600080fd5b6128eb8c35612ea4565b8b359a506128fc60208d0135612ea4565b60208c0135995061290f60408d016127f0565b985061291d60608d016127f0565b975067ffffffffffffffff8060808e0135111561293957600080fd5b6129498e60808f01358f01612800565b909850965060a08d013581101561295f57600080fd5b506129708d60a08e01358e01612800565b909550935061298160c08d016127f0565b925061298f60e08d016127f0565b91506101008c013590509295989b509295989b9093969950565b600080600080600080600060a0888a0312156129c457600080fd5b87356129cf81612ea4565b965060208801356129df81612ea4565b955060408801356129ef81612ea4565b9450606088013567ffffffffffffffff80821115612a0c57600080fd5b612a188b838c01612800565b909650945060808a0135915080821115612a3157600080fd5b50612a3e8a828b01612800565b989b979a50959850939692959293505050565b600080600060608486031215612a6657600080fd5b8335612a7181612ea4565b92506020840135612a8181612ea4565b929592945050506040919091013590565b60008060408385031215612aa557600080fd5b8235612ab081612ea4565b946020939093013593505050565b600060208284031215612ad057600080fd5b8151801515811461207e57600080fd5b600060208284031215612af257600080fd5b5035919050565b600060208284031215612b0b57600080fd5b5051919050565b600060208284031215612b2457600080fd5b815160ff8116811461207e57600080fd5b8060005b6003811015612b58578151845260209384019390910190600101612b39565b50505050565b60008251612b70818460208701612e1b565b9190910192915050565b60808101612b888285612b35565b8260608301529392505050565b6020815260008251806020840152612bb4816040850160208701612e1b565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8281526080810161207e6020830184612b35565b60008219821115612cd357612cd3612e62565b500190565b600082612cf557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612d35578160001904821115612d1b57612d1b612e62565b80851615612d2857918102915b93841c9390800290612cff565b509250929050565b600061207e8383600082612d535750600161201b565b81612d605750600061201b565b8160018114612d765760028114612d8057612d9c565b600191505061201b565b60ff841115612d9157612d91612e62565b50506001821b61201b565b5060208310610133831016604e8410600b8410161715612dbf575081810a61201b565b612dc98383612cfa565b8060001904821115612ddd57612ddd612e62565b029392505050565b6000816000190483118215151615612dff57612dff612e62565b500290565b600082821015612e1657612e16612e62565b500390565b60005b83811015612e36578181015183820152602001612e1e565b83811115612b585750506000910152565b6000600019821415612e5b57612e5b612e62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114611e9357600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220560344b59118d500929e452b63d4097607c8a6d317a3637e778ab836a8efdfce64736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061018e5760003560e01c8063790fcf9f116100de578063c7af335211610097578063d7dc031211610071578063d7dc031214610357578063d9caed121461036a578063dbe55e561461037d578063de5f62681461039057600080fd5b8063c7af335214610329578063cd3b021214610331578063d38bfff41461034457600080fd5b8063790fcf9f146102a2578063853828b6146102b55780639136616a146102bd5780639a6acf20146102d0578063aa388af6146102e3578063ad1728cb1461032157600080fd5b80631a89a4d41161014b57806347e7ef241161012557806347e7ef241461025d5780635653b414146102705780635d36b190146102875780635f5152261461028f57600080fd5b80631a89a4d41461022457806327e5140f14610237578063430bf08a1461024a57600080fd5b80630242241d146101935780630c340a241461019d5780630ed57b3a146101c25780630fc3b4c4146101d55780631072cbea146101fe578063125f9e3314610211575b600080fd5b61019b610398565b005b6101a561064f565b6040516001600160a01b0390911681526020015b60405180910390f35b61019b6101d0366004612886565b61066c565b6101a56101e336600461284c565b6035602052600090815260409020546001600160a01b031681565b61019b61020c366004612a92565b61069e565b6037546101a5906001600160a01b031681565b61019b6102323660046128bf565b6106de565b61019b61024536600461284c565b6108cf565b6034546101a5906001600160a01b031681565b61019b61026b366004612a92565b61095c565b61027960385481565b6040519081526020016101b9565b61019b610bbf565b61027961029d36600461284c565b610c65565b61019b6102b03660046129a9565b610dac565b61019b610eb3565b61019b6102cb366004612ae0565b611148565b61019b6102de36600461284c565b611313565b6103116102f136600461284c565b6001600160a01b0390811660009081526035602052604090205416151590565b60405190151581526020016101b9565b61019b6113a0565b610311611459565b61019b61033f366004612ae0565b61148a565b61019b61035236600461284c565b6114ef565b60a0546101a5906001600160a01b031681565b61019b610378366004612a51565b611593565b6033546101a5906001600160a01b031681565b61019b61187b565b6034546001600160a01b031633146103cb5760405162461bcd60e51b81526004016103c290612bc8565b60405180910390fd5b600080516020612eba833981519152805460028114156103fd5760405162461bcd60e51b81526004016103c290612c84565b60028255609f60009054906101000a90046001600160a01b03166001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561045157600080fd5b505af1158015610465573d6000803e3d6000fd5b50506037546040516370a0823160e01b81523060048201526001600160a01b0390911692506000915082906370a082319060240160206040518083038186803b1580156104b157600080fd5b505afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e99190612af9565b603454603754604080516001600160a01b03938416815292909116602083015281018290529091507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610558906001600160a01b03848116911683611b6b565b60a0546040516370a0823160e01b81523060048201526001600160a01b039091169081906370a082319060240160206040518083038186803b15801561059d57600080fd5b505afa1580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190612af9565b60345460a054604080516001600160a01b03938416815292909116602083015281018290529092507ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a1603454610644906001600160a01b03838116911684611b6b565b505050600182555050565b6000610667600080516020612eda8339815191525490565b905090565b610674611459565b6106905760405162461bcd60e51b81526004016103c290612bff565b61069a8282611bd3565b5050565b6106a6611459565b6106c25760405162461bcd60e51b81526004016103c290612bff565b61069a6106cd61064f565b6001600160a01b0384169083611b6b565b6106e6611459565b6107025760405162461bcd60e51b81526004016103c290612bff565b600054610100900460ff168061071b575060005460ff16155b6107375760405162461bcd60e51b81526004016103c290612c36565b600054610100900460ff16158015610759576000805461ffff19166101011790555b600387146107a95760405162461bcd60e51b815260206004820152601e60248201527f4d75737420686176652065786163746c7920746872656520617373657473000060448201526064016103c2565b609e80546001600160a01b038087166001600160a01b031992831617909255609f805486841690831617905560a184905560a08054928c169290911691909117905585856000816107fc576107fc612e8e565b9050602002016020810190610811919061284c565b609d60006101000a8154816001600160a01b0302191690836001600160a01b031602179055506108a78c8c8c8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d918291850190849080828437600092019190915250611d3892505050565b6108af611e20565b80156108c1576000805461ff00191690555b505050505050505050505050565b6108d7611459565b6108f35760405162461bcd60e51b81526004016103c290612bff565b60a054604080516001600160a01b03928316815291831660208301527f144d9f91f22eaef5ccf23cd53ea617c4c518097dd96a5176910746f825d0a5b8910160405180910390a160a080546001600160a01b0319166001600160a01b0392909216919091179055565b6034546001600160a01b031633146109865760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156109b85760405162461bcd60e51b81526004016103c290612c84565b6002825560008311610a055760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b60448201526064016103c2565b603354604080516001600160a01b03928316815260208101869052918616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a2610a576127d2565b6000610a6286611e96565b905084828260038110610a7757610a77612e8e565b60200201526033546001600160a01b03166000610a9388611f32565b90506000610b1d836001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad357600080fd5b505afa158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b9190612af9565b610b178a601286612021565b90612085565b90506000610b44610b3d662386f26fc10000670de0b6b3a7640000612e04565b83906120ae565b604051634515cef360e01b81529091506001600160a01b03851690634515cef390610b759089908590600401612b7a565b600060405180830381600087803b158015610b8f57600080fd5b505af1158015610ba3573d6000803e3d6000fd5b50505050610baf6120c3565b5050505050506001825550505050565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610c5a5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b60648201526084016103c2565b610c633361221d565b565b6001600160a01b03818116600090815260356020526040812054909116610cc25760405162461bcd60e51b8152602060048201526011602482015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b60448201526064016103c2565b6000610ccc6122de565b6033549093506001600160a01b03169150508115610da5576000816001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b158015610d1f57600080fd5b505afa158015610d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d579190612af9565b90506000670de0b6b3a7640000610d6e8386612de5565b610d789190612cd8565b90506000610d8587611f32565b90506003610d9583836012612021565b610d9f9190612cd8565b95505050505b5050919050565b610db4611459565b610dd05760405162461bcd60e51b81526004016103c290612bff565b600054610100900460ff1680610de9575060005460ff16155b610e055760405162461bcd60e51b81526004016103c290612c36565b600054610100900460ff16158015610e27576000805461ffff19166101011790555b610e9788888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611d3892505050565b8015610ea9576000805461ff00191690555b5050505050505050565b6034546001600160a01b0316331480610ee45750610ecf61064f565b6001600160a01b0316336001600160a01b0316145b610f3c5760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b60648201526084016103c2565b600080516020612eba83398151915280546002811415610f6e5760405162461bcd60e51b81526004016103c290612c84565b60028255600080610f7d6122de565b9250925050610f8b826123ed565b6040805160608101825260008082526020820181905281830152603354915163ecb586a560e01b815290916001600160a01b031690819063ecb586a590610fd89086908690600401612cac565b600060405180830381600087803b158015610ff257600080fd5b505af1158015611006573d6000803e3d6000fd5b5050505060005b60365481101561113b5760405163c661065760e01b8152600481018290526000906001600160a01b0384169063c66106579060240160206040518083038186803b15801561105a57600080fd5b505afa15801561106e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110929190612869565b6034546040516370a0823160e01b8152306004820152919250611128916001600160a01b03918216918416906370a082319060240160206040518083038186803b1580156110df57600080fd5b505afa1580156110f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111179190612af9565b6001600160a01b0384169190611b6b565b508061113381612e47565b91505061100d565b5050505050600182555050565b611150611459565b61116c5760405162461bcd60e51b81526004016103c290612bff565b60365481106111ad5760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b60448201526064016103c2565b6000603682815481106111c2576111c2612e8e565b60009182526020808320909101546001600160a01b039081168084526035909252604090922054603654919350909116906111ff90600190612e04565b831015611281576036805461121690600190612e04565b8154811061122657611226612e8e565b600091825260209091200154603680546001600160a01b03909216918590811061125257611252612e8e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b603680548061129257611292612e78565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526035855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b61131b611459565b6113375760405162461bcd60e51b81526004016103c290612bff565b603754604080516001600160a01b03928316815291831660208301527f6000690cf6fd1e69830cc1142bc52655402f4a58db681849f61c3c8fb322ff8a910160405180910390a1603780546001600160a01b0319166001600160a01b0392909216919091179055565b6113a8611459565b6113c45760405162461bcd60e51b81526004016103c290612bff565b600080516020612eba833981519152805460028114156113f65760405162461bcd60e51b81526004016103c290612c84565b60028255611402611e20565b60005b6036548110156114515761143f6036828154811061142557611425612e8e565b6000918252602090912001546001600160a01b0316612455565b8061144981612e47565b915050611405565b505060019055565b6000611471600080516020612eda8339815191525490565b6001600160a01b0316336001600160a01b031614905090565b611492611459565b6114ae5760405162461bcd60e51b81526004016103c290612bff565b60385460408051918252602082018390527f01538952e8f491e3569a11bf3935ca2fa917ea85ec938dac52e696fbb76d8cc6910160405180910390a1603855565b6114f7611459565b6115135760405162461bcd60e51b81526004016103c290612bff565b61153b817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b031661155b600080516020612eda8339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b6034546001600160a01b031633146115bd5760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156115ef5760405162461bcd60e51b81526004016103c290612c84565b60028255600083116116345760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b60448201526064016103c2565b6001600160a01b0384811660008181526035602090815260409182902054825194168452830186905290917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a26000806116956122de565b925050915060006116a587611e96565b60335460405163cc2b27d760e01b815260048101859052600f83900b602482015291925082916001600160a01b0390911690600090829063cc2b27d79060440160206040518083038186803b1580156116fd57600080fd5b505afa158015611711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117359190612af9565b90506000816117448b88612de5565b61174e9190612cd8565b905080861161179f5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420334352562062616c616e63650000000000000060448201526064016103c2565b808710156117b9576117b96117b48883612e04565b6123ed565b600060405180606001604052806000815260200160008152602001600081525090508a8187600381106117ee576117ee612e8e565b60200201526040516327f6ba8360e21b81526001600160a01b03851690639fdaea0c906118219084908690600401612b7a565b600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b50611868925050506001600160a01b038d168e8d611b6b565b5050505050505050600182555050505050565b6034546001600160a01b031633146118a55760405162461bcd60e51b81526004016103c290612bc8565b600080516020612eba833981519152805460028114156118d75760405162461bcd60e51b81526004016103c290612c84565b6002825560408051606081018252600080825260208083018290528284018290526033548451630176f71760e71b81529451939492936001600160a01b03909116928492849263bb7b8b80926004808201939291829003018186803b15801561193f57600080fd5b505afa158015611953573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119779190612af9565b905060005b603654811015611ada5760006036828154811061199b5761199b612e8e565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b1580156119e957600080fd5b505afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190612af9565b90508015611ac5576000611a3483611e96565b905081888260038110611a4957611a49612e8e565b60200201526000611a5984611f32565b9050611a6b86610b1785601285612021565b611a759089612cc0565b603354604080516001600160a01b03928316815260208101879052929a50908616917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a250505b50508080611ad290612e47565b91505061197c565b506000611b00611af9662386f26fc10000670de0b6b3a7640000612e04565b85906120ae565b604051634515cef360e01b81529091506001600160a01b03841690634515cef390611b319088908590600401612b7a565b600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505061113b6120c3565b6040516001600160a01b038316602482015260448101829052611bce90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261248e565b505050565b6001600160a01b038281166000908152603560205260409020541615611c305760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b60448201526064016103c2565b6001600160a01b03821615801590611c5057506001600160a01b03811615155b611c905760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b60448201526064016103c2565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a261069a8282612560565b603380546001600160a01b038088166001600160a01b031992831617909255603480548784169083161790556037805492861692909116919091179055815181518114611dbe5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b60448201526064016103c2565b60005b81811015611e1757611e05848281518110611dde57611dde612e8e565b6020026020010151848381518110611df857611df8612e8e565b6020026020010151611bd3565b80611e0f81612e47565b915050611dc1565b50505050505050565b609d546033546001600160a01b0391821691611e40918391166000612569565b603354611e5c906001600160a01b038381169116600019612569565b609e54611e77906001600160a01b0383811691166000612569565b609e54611e93906001600160a01b038381169116600019612569565b50565b6000805b6003811015611ef357826001600160a01b031660368281548110611ec057611ec0612e8e565b6000918252602090912001546001600160a01b03161415611ee15792915050565b80611eeb81612e47565b915050611e9a565b5060405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59080cdc1bdbdb08185cdcd95d606a1b60448201526064016103c2565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611f6e57600080fd5b505afa158015611f82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa69190612b12565b60ff16905060048110158015611fbd575060128111155b61201b5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b60648201526084016103c2565b92915050565b6000818311156120515761204a6120388385612e04565b61204390600a612d3d565b859061268d565b935061207b565b8183101561207b576120786120668484612e04565b61207190600a612d3d565b8590612699565b93505b50825b9392505050565b60008061209a84670de0b6b3a764000061268d565b90506120a68184612699565b949350505050565b600061207e8383670de0b6b3a76400006126a5565b609d54609e5460a1546040516370a0823160e01b81523060048201526001600160a01b039384169360009316916343a0d0669185906370a082319060240160206040518083038186803b15801561211957600080fd5b505afa15801561212d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121519190612af9565b6040516001600160e01b031960e085901b1681526004810192909252602482015260016044820152606401602060405180830381600087803b15801561219657600080fd5b505af11580156121aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ce9190612abe565b90508061069a5760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f206465706f73697420746f20436f6e766578000000000060448201526064016103c2565b6001600160a01b0381166122735760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f72206973206164647265737328302900000000000060448201526064016103c2565b806001600160a01b0316612293600080516020612eda8339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3611e9381600080516020612eda83398151915255565b609d546040516370a0823160e01b8152306004820152600091829182916001600160a01b0316906370a082319060240160206040518083038186803b15801561232657600080fd5b505afa15801561233a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235e9190612af9565b609f546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a082319060240160206040518083038186803b1580156123a257600080fd5b505afa1580156123b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123da9190612af9565b91506123e68284612cc0565b9050909192565b609f54604051636197390160e11b815260048101839052600160248201526001600160a01b039091169063c32e720290604401600060405180830381600087803b15801561243a57600080fd5b505af115801561244e573d6000803e3d6000fd5b5050505050565b6033548190612472906001600160a01b0380841691166000612569565b60335461069a906001600160a01b038381169116600019612569565b60006124e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126c79092919063ffffffff16565b805190915015611bce57808060200190518101906125019190612abe565b611bce5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103c2565b61069a82612455565b8015806125f25750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156125b857600080fd5b505afa1580156125cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f09190612af9565b155b61265d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016103c2565b6040516001600160a01b038316602482015260448101829052611bce90849063095ea7b360e01b90606401611b97565b600061207e8284612de5565b600061207e8284612cd8565b6000806126b2858561268d565b90506126be8184612699565b95945050505050565b60606120a6848460008585843b6127205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c2565b600080866001600160a01b0316858760405161273c9190612b5e565b60006040518083038185875af1925050503d8060008114612779576040519150601f19603f3d011682016040523d82523d6000602084013e61277e565b606091505b509150915061278e828286612799565b979650505050505050565b606083156127a857508161207e565b8251156127b85782518084602001fd5b8160405162461bcd60e51b81526004016103c29190612b95565b60405180606001604052806003906020820280368337509192915050565b80356127fb81612ea4565b919050565b60008083601f84011261281257600080fd5b50813567ffffffffffffffff81111561282a57600080fd5b6020830191508360208260051b850101111561284557600080fd5b9250929050565b60006020828403121561285e57600080fd5b813561207e81612ea4565b60006020828403121561287b57600080fd5b815161207e81612ea4565b6000806040838503121561289957600080fd5b82356128a481612ea4565b915060208301356128b481612ea4565b809150509250929050565b60008060008060008060008060008060006101208c8e0312156128e157600080fd5b6128eb8c35612ea4565b8b359a506128fc60208d0135612ea4565b60208c0135995061290f60408d016127f0565b985061291d60608d016127f0565b975067ffffffffffffffff8060808e0135111561293957600080fd5b6129498e60808f01358f01612800565b909850965060a08d013581101561295f57600080fd5b506129708d60a08e01358e01612800565b909550935061298160c08d016127f0565b925061298f60e08d016127f0565b91506101008c013590509295989b509295989b9093969950565b600080600080600080600060a0888a0312156129c457600080fd5b87356129cf81612ea4565b965060208801356129df81612ea4565b955060408801356129ef81612ea4565b9450606088013567ffffffffffffffff80821115612a0c57600080fd5b612a188b838c01612800565b909650945060808a0135915080821115612a3157600080fd5b50612a3e8a828b01612800565b989b979a50959850939692959293505050565b600080600060608486031215612a6657600080fd5b8335612a7181612ea4565b92506020840135612a8181612ea4565b929592945050506040919091013590565b60008060408385031215612aa557600080fd5b8235612ab081612ea4565b946020939093013593505050565b600060208284031215612ad057600080fd5b8151801515811461207e57600080fd5b600060208284031215612af257600080fd5b5035919050565b600060208284031215612b0b57600080fd5b5051919050565b600060208284031215612b2457600080fd5b815160ff8116811461207e57600080fd5b8060005b6003811015612b58578151845260209384019390910190600101612b39565b50505050565b60008251612b70818460208701612e1b565b9190910192915050565b60808101612b888285612b35565b8260608301529392505050565b6020815260008251806020840152612bb4816040850160208701612e1b565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b8281526080810161207e6020830184612b35565b60008219821115612cd357612cd3612e62565b500190565b600082612cf557634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115612d35578160001904821115612d1b57612d1b612e62565b80851615612d2857918102915b93841c9390800290612cff565b509250929050565b600061207e8383600082612d535750600161201b565b81612d605750600061201b565b8160018114612d765760028114612d8057612d9c565b600191505061201b565b60ff841115612d9157612d91612e62565b50506001821b61201b565b5060208310610133831016604e8410600b8410161715612dbf575081810a61201b565b612dc98383612cfa565b8060001904821115612ddd57612ddd612e62565b029392505050565b6000816000190483118215151615612dff57612dff612e62565b500290565b600082821015612e1657612e16612e62565b500390565b60005b83811015612e36578181015183820152602001612e1e565b83811115612b585750506000910152565b6000600019821415612e5b57612e5b612e62565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114611e9357600080fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220560344b59118d500929e452b63d4097607c8a6d317a3637e778ab836a8efdfce64736f6c63430008070033", "devdoc": { "kind": "dev", "methods": { @@ -647,7 +692,7 @@ "details": "Claim Governance of the contract to a new account (`newGovernor`). Can only be called by the new Governor." }, "collectRewardToken()": { - "details": "Collect accumulated CRV and send to Vault." + "details": "Collect accumulated CRV and CVX and send to Vault." }, "deposit(address,uint256)": { "details": "Deposit asset into the Curve 3Pool", @@ -665,13 +710,13 @@ "initialize(address,address,address,address,address[],address[],address,address,uint256)": { "params": { "_assets": "Addresses of supported assets. MUST be passed in the same order as returned by coins on the pool contract, i.e. DAI, USDC, USDT", - "_crvRewardTokenAddress": "Address of CRV *yes we get both*", "_cvxDepositorAddress": "Address of the Convex depositor(AKA booster) for this pool", "_cvxDepositorPTokenId": "Pid of the pool referred to by Depositor and staker", - "_cvxRewardStakerAddress": "Address of the CRVX rewards staker", + "_cvxRewardStakerAddress": "Address of the CVX rewards staker", + "_cvxRewardTokenAddress": "Address of CVX *yes we get both*", "_pTokens": "Platform Token corresponding addresses", "_platformAddress": "Address of the Curve 3pool", - "_rewardTokenAddress": "Address of CRVX", + "_rewardTokenAddress": "Address of CRV", "_vaultAddress": "Address of the vault" } }, @@ -697,6 +742,12 @@ "safeApproveAllTokens()": { "details": "Approve the spending of all assets by their corresponding pool tokens, if for some reason is it necessary." }, + "setCvxRewardTokenAddress(address)": { + "details": "Set the CVX reward token address.", + "params": { + "_cvxRewardTokenAddress": "Address of the reward token" + } + }, "setPTokenAddress(address,address)": { "details": "Provide support for asset by passing its pToken address. This method can only be called by the system Governor", "params": { @@ -761,7 +812,7 @@ "storageLayout": { "storage": [ { - "astId": 18084, + "astId": 17687, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "initialized", "offset": 0, @@ -769,7 +820,7 @@ "type": "t_bool" }, { - "astId": 18087, + "astId": 17690, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "initializing", "offset": 1, @@ -777,7 +828,7 @@ "type": "t_bool" }, { - "astId": 18127, + "astId": 17730, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "______gap", "offset": 0, @@ -785,7 +836,7 @@ "type": "t_array(t_uint256)50_storage" }, { - "astId": 18199, + "astId": 17802, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "platformAddress", "offset": 0, @@ -793,7 +844,7 @@ "type": "t_address" }, { - "astId": 18201, + "astId": 17804, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "vaultAddress", "offset": 0, @@ -801,7 +852,7 @@ "type": "t_address" }, { - "astId": 18205, + "astId": 17808, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "assetToPToken", "offset": 0, @@ -809,7 +860,7 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 18208, + "astId": 17811, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "assetsMapped", "offset": 0, @@ -817,7 +868,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 18210, + "astId": 17813, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "rewardTokenAddress", "offset": 0, @@ -825,7 +876,7 @@ "type": "t_address" }, { - "astId": 18212, + "astId": 17815, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "rewardLiquidationThreshold", "offset": 0, @@ -833,7 +884,7 @@ "type": "t_uint256" }, { - "astId": 18216, + "astId": 17819, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "_reserved", "offset": 0, @@ -841,7 +892,7 @@ "type": "t_array(t_int256)100_storage" }, { - "astId": 13940, + "astId": 13513, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "pTokenAddress", "offset": 0, @@ -849,7 +900,7 @@ "type": "t_address" }, { - "astId": 15267, + "astId": 14846, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "cvxDepositorAddress", "offset": 0, @@ -857,7 +908,7 @@ "type": "t_address" }, { - "astId": 15269, + "astId": 14848, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "cvxRewardStakerAddress", "offset": 0, @@ -865,15 +916,15 @@ "type": "t_address" }, { - "astId": 15271, + "astId": 14850, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", - "label": "crvRewardTokenAddress", + "label": "cvxRewardTokenAddress", "offset": 0, "slot": "160", "type": "t_address" }, { - "astId": 15273, + "astId": 14852, "contract": "contracts/strategies/ConvexStrategy.sol:ConvexStrategy", "label": "cvxDepositorPTokenId", "offset": 0, diff --git a/contracts/deployments/mainnet/solcInputs/a9ed004f4d203a17c07bb1c3b7c6c7b7.json b/contracts/deployments/mainnet/solcInputs/a9ed004f4d203a17c07bb1c3b7c6c7b7.json new file mode 100644 index 0000000000..37535b2318 --- /dev/null +++ b/contracts/deployments/mainnet/solcInputs/a9ed004f4d203a17c07bb1c3b7c6c7b7.json @@ -0,0 +1,317 @@ +{ + "language": "Solidity", + "sources": { + "contracts/buyback/Buyback.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { Governable } from \"../governance/Governable.sol\";\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport { UniswapV3Router } from \"../interfaces/UniswapV3Router.sol\";\n\ncontract Buyback is Governable {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n event UniswapUpdated(address _address);\n event BuybackFailed(bytes data);\n\n // Address of Uniswap\n address public uniswapAddr;\n\n // Address of OUSD Vault\n address public immutable vaultAddr;\n\n // Swap from OUSD\n IERC20 immutable ousd;\n\n // Swap to OGN\n IERC20 immutable ogn;\n\n // USDT for Uniswap path\n IERC20 immutable usdt;\n\n // WETH for Uniswap path\n IERC20 immutable weth9;\n\n // Oracles\n address immutable ognEthOracle;\n address immutable ethUsdOracle;\n\n constructor(\n address _uniswapAddr,\n address _vaultAddr,\n address _ousd,\n address _ogn,\n address _usdt,\n address _weth9,\n address _ognEthOracle,\n address _ethUsdOracle\n ) {\n uniswapAddr = _uniswapAddr;\n vaultAddr = _vaultAddr;\n ousd = IERC20(_ousd);\n ogn = IERC20(_ogn);\n usdt = IERC20(_usdt);\n weth9 = IERC20(_weth9);\n ognEthOracle = _ognEthOracle;\n ethUsdOracle = _ethUsdOracle;\n // Give approval to Uniswap router for OUSD, this is handled\n // by setUniswapAddr in the production contract\n IERC20(_ousd).safeApprove(uniswapAddr, 0);\n IERC20(_ousd).safeApprove(uniswapAddr, type(uint256).max);\n }\n\n /**\n * @dev Verifies that the caller is the OUSD Vault.\n */\n modifier onlyVault() {\n require(vaultAddr == msg.sender, \"Caller is not the Vault\");\n _;\n }\n\n /**\n * @dev Set address of Uniswap for performing liquidation of strategy reward\n * tokens. Setting to 0x0 will pause swaps.\n * @param _address Address of Uniswap\n */\n function setUniswapAddr(address _address) external onlyGovernor {\n uniswapAddr = _address;\n if (uniswapAddr == address(0)) return;\n // Give Uniswap unlimited OUSD allowance\n ousd.safeApprove(uniswapAddr, 0);\n ousd.safeApprove(uniswapAddr, type(uint256).max);\n emit UniswapUpdated(_address);\n }\n\n /**\n * @dev Execute a swap of OGN for OUSD via Uniswap or Uniswap compatible\n * protocol (e.g. Sushiswap)\n **/\n function swap() external onlyVault nonReentrant {\n uint256 sourceAmount = ousd.balanceOf(address(this));\n if (sourceAmount < 1000 * 1e18) return;\n if (uniswapAddr == address(0)) return;\n // 97% should be the limits of our oracle errors.\n // If this swap sometimes skips when it should succeed, that’s okay,\n // the amounts will get get sold the next time this runs,\n // when presumably the oracles are more accurate.\n uint256 minExpected = expectedOgnPerOUSD(sourceAmount).mul(97).div(100);\n\n UniswapV3Router.ExactInputParams memory params = UniswapV3Router\n .ExactInputParams({\n path: abi.encodePacked(\n ousd,\n uint24(500), // Pool fee, ousd -> usdt\n usdt,\n uint24(3000), // Pool fee, usdt -> weth9\n weth9,\n uint24(3000), // Pool fee, weth9 -> ogn\n ogn\n ),\n recipient: address(this),\n deadline: uint256(block.timestamp.add(1000)),\n amountIn: sourceAmount,\n amountOutMinimum: minExpected\n });\n\n // Don't revert everything, even if the buyback fails.\n // We want the overall transaction to continue regardless.\n // We don't need to look at the return data, since the amount will\n // be above the minExpected.\n (bool success, bytes memory data) = uniswapAddr.call(\n abi.encodeWithSignature(\n \"exactInput((bytes,address,uint256,uint256,uint256))\",\n params\n )\n );\n if (!success) {\n emit BuybackFailed(data);\n }\n }\n\n function expectedOgnPerOUSD(uint256 ousdAmount)\n public\n view\n returns (uint256)\n {\n return\n ousdAmount.mul(uint256(1e26)).div( // ognEth is 18 decimal. ethUsd is 8 decimal.\n _price(ognEthOracle).mul(_price(ethUsdOracle))\n );\n }\n\n function _price(address _feed) internal view returns (uint256) {\n require(_feed != address(0), \"Asset not available\");\n (, int256 _iprice, , , ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n require(_iprice > 0, \"Price must be greater than zero\");\n return uint256(_iprice);\n }\n\n /**\n * @notice Owner function to withdraw a specific amount of a token\n * @param token token to be transferered\n * @param amount amount of the token to be transferred\n */\n function transferToken(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n}\n" + }, + "contracts/governance/Governable.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 private constant governorPosition =\n 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n // keccak256(\"OUSD.pending.governor\");\n bytes32 private constant pendingGovernorPosition =\n 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n // keccak256(\"OUSD.reentry.status\");\n bytes32 private constant reentryStatusPosition =\n 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() {\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" + }, + "contracts/interfaces/chainlink/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\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(\n address sender,\n address recipient,\n uint256 amount\n ) 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/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.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 IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) 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 require(\n (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(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\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. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\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) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\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 *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\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 *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\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 *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting 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 *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\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 * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting 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 *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\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 *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "contracts/interfaces/UniswapV3Router.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n// -- Solididy v0.5.x compatible interface\ninterface UniswapV3Router {\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\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 // This method relies on extcodesize, which returns 0 for contracts in\n // construction, since the code is only stored at the end of the\n // constructor execution.\n\n uint256 size;\n assembly {\n size := extcodesize(account)\n }\n return size > 0;\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 function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/utils/InitializableAbstractStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\n\nabstract contract 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 event RewardTokenAddressUpdated(address _oldAddress, address _newAddress);\n event RewardLiquidationThresholdUpdated(\n uint256 _oldThreshold,\n uint256 _newThreshold\n );\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 // Reserved for future expansion\n int256[100] private _reserved;\n\n /**\n * @dev Internal initialize function, to set up initial internal state\n * @param _platformAddress Generic 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 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 Collect accumulated reward token and send to Vault.\n */\n function collectRewardToken() external virtual 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 /**\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 emit RewardTokenAddressUpdated(rewardTokenAddress, _rewardTokenAddress);\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 emit RewardLiquidationThresholdUpdated(\n rewardLiquidationThreshold,\n _threshold\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)\n internal\n virtual;\n\n function safeApproveAllTokens() external virtual;\n\n /**\n * @dev Deposit an 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 virtual;\n\n /**\n * @dev Deposit balance of all supported assets into the platform\n */\n function depositAll() external virtual;\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 virtual;\n\n /**\n * @dev Withdraw all assets from strategy sending assets to Vault.\n */\n function withdrawAll() external virtual;\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 virtual\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 virtual returns (bool);\n}\n" + }, + "contracts/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nabstract contract Initializable {\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 protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(\n initializing || !initialized,\n \"Initializable: contract is already initialized\"\n );\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 uint256[50] private ______gap;\n}\n" + }, + "contracts/strategies/CompoundStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Compound Strategy\n * @notice Investment strategy for investing stablecoins via Compound\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICERC20 } from \"./ICompound.sol\";\nimport { IComptroller } from \"../interfaces/IComptroller.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\ncontract CompoundStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n event SkippedWithdrawal(address asset, uint256 amount);\n\n /**\n * @dev Collect accumulated COMP and send to Vault.\n */\n function collectRewardToken() external override onlyVault nonReentrant {\n // Claim COMP from Comptroller\n ICERC20 cToken = _getCTokenFor(assetsMapped[0]);\n IComptroller comptroller = IComptroller(cToken.comptroller());\n comptroller.claimComp(address(this));\n // Transfer COMP to Vault\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 /**\n * @dev Deposit asset into Compound\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 override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\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 */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\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 Deposit the entire balance of any supported asset into Compound\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\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 */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\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 override 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 override\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 * exchangeRate) / 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)\n external\n view\n override\n returns (bool)\n {\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 override {\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, type(uint256).max);\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 The cToken for the approval\n */\n function _abstractSetPToken(address _asset, address _cToken)\n internal\n override\n {\n // Safe approval\n IERC20(_asset).safeApprove(_cToken, 0);\n IERC20(_asset).safeApprove(_cToken, type(uint256).max);\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 * 1e18) / exchangeRate;\n }\n}\n" + }, + "contracts/strategies/ICompound.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 /**\n * @notice Address of the Compound Comptroller.\n */\n function comptroller() external view returns (address);\n}\n" + }, + "contracts/interfaces/IComptroller.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IComptroller {\n /**\n * @notice Claim all the comp accrued by holder in all markets\n * @param holder The address to claim COMP for\n */\n function claimComp(address holder) external;\n}\n" + }, + "contracts/mocks/MockCToken.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { ICERC20 } from \"../strategies/ICompound.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\n\ncontract MockCToken is ICERC20, ERC20 {\n using StableMath for uint256;\n\n IERC20 public underlyingToken;\n // underlying = cToken * exchangeRate\n // cToken = underlying / exchangeRate\n uint256 exchangeRate;\n address public override comptroller;\n\n constructor(ERC20 _underlyingToken, address _comptroller)\n ERC20(\"cMock\", \"cMK\")\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 comptroller = _comptroller;\n }\n\n function decimals() public pure override returns (uint8) {\n return 8;\n }\n\n function mint(uint256 mintAmount) public override 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 override 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)\n external\n override\n returns (uint256)\n {\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)\n external\n view\n override\n returns (uint256)\n {\n uint256 cTokenBal = this.balanceOf(owner);\n return cTokenBal.mulTruncate(exchangeRate);\n }\n\n function balanceOf(address owner)\n public\n view\n override(ICERC20, ERC20)\n returns (uint256)\n {\n return ERC20.balanceOf(owner);\n }\n\n function updateExchangeRate()\n internal\n view\n returns (uint256 newExchangeRate)\n {\n uint256 factor = 100002 * (10**13); // 0.002%\n newExchangeRate = exchangeRate.mulTruncate(factor);\n }\n\n function exchangeRateStored() external view override returns (uint256) {\n return exchangeRate;\n }\n\n function supplyRatePerBlock() external pure override returns (uint256) {\n return 141 * (10**8);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.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 {ERC20PresetMinterPauser}.\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 Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * 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, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override 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 virtual override 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. This is the value {ERC20} uses, unless this function is\n * overridden;\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 virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override 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 virtual override 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 virtual override 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 virtual override 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 *\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(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\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 virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + 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 virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This 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(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(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 * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(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 virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This 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(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\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 Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "contracts/utils/StableMath.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/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 to Decimals to scale to\n * @param from Decimals to scale from\n */\n function scaleBy(\n uint256 x,\n uint256 to,\n uint256 from\n ) internal pure returns (uint256) {\n if (to > from) {\n x = x.mul(10**(to - from));\n } else if (to < from) {\n x = x.div(10**(from - to));\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 9e36 / 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" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.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 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 */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "contracts/vault/VaultAdmin.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IUniswapV2Router } from \"../interfaces/uniswap/IUniswapV2Router02.sol\";\nimport \"./VaultStorage.sol\";\n\ncontract VaultAdmin is VaultStorage {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n\n /**\n * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n */\n modifier onlyVaultOrGovernorOrStrategist() {\n require(\n msg.sender == address(this) ||\n msg.sender == strategistAddr ||\n isGovernor(),\n \"Caller is not the Vault, Governor, or Strategist\"\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)\n external\n onlyGovernorOrStrategist\n {\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 for (uint256 i = 0; i < swapTokens.length; i++) {\n // Revoke swap token approvals for old address\n IERC20(swapTokens[i]).safeApprove(uniswapAddr, 0);\n }\n uniswapAddr = _address;\n for (uint256 i = 0; i < swapTokens.length; i++) {\n // Add swap token approvals for new address\n IERC20(swapTokens[i]).safeApprove(uniswapAddr, type(uint256).max);\n }\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 // If its a zero address being passed for the strategy we are removing\n // the default strategy\n if (_strategy != address(0)) {\n // Make sure the strategy meets some criteria\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 }\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 // Verify that our oracle supports the asset\n // slither-disable-next-line unused-return\n IOracle(priceProvider).price(_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 for (uint256 i = 0; i < allAssets.length; i++) {\n require(\n assetDefaultStrategies[allAssets[i]] != _addr,\n \"Strategy is default for an asset\"\n );\n }\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[\n allStrategies.length - 1\n ];\n allStrategies.pop();\n\n // Mark the strategy as not supported\n strategies[_addr].isSupported = false;\n\n // Withdraw all assets\n IStrategy strategy = IStrategy(_addr);\n strategy.withdrawAll();\n\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\n /**\n * @dev Add a swap token to the tokens that get liquidated for stablecoins\n * whenever swap is called. The token must have a valid feed registered\n * with the price provider.\n * @param _addr Address of the token\n */\n function addSwapToken(address _addr) external onlyGovernor {\n for (uint256 i = 0; i < swapTokens.length; i++) {\n if (swapTokens[i] == _addr) {\n revert(\"Swap token already added\");\n }\n }\n\n // Revert if feed does not exist\n IOracle(priceProvider).price(_addr);\n\n swapTokens.push(_addr);\n\n // Give Uniswap infinte approval\n if (uniswapAddr != address(0)) {\n IERC20 token = IERC20(_addr);\n token.safeApprove(uniswapAddr, 0);\n token.safeApprove(uniswapAddr, type(uint256).max);\n }\n\n emit SwapTokenAdded(_addr);\n }\n\n /**\n * @dev Remove a swap token from the tokens that get liquidated for stablecoins.\n * @param _addr Address of the token\n */\n function removeSwapToken(address _addr) external onlyGovernor {\n uint256 swapTokenIndex = swapTokens.length;\n for (uint256 i = 0; i < swapTokens.length; i++) {\n if (swapTokens[i] == _addr) {\n swapTokenIndex = i;\n break;\n }\n }\n\n require(swapTokenIndex != swapTokens.length, \"Swap token not added\");\n\n // Shift everything after the index element by 1\n for (uint256 i = swapTokenIndex; i < swapTokens.length - 1; i++) {\n swapTokens[i] = swapTokens[i + 1];\n }\n swapTokens.pop();\n\n if (uniswapAddr != address(0)) {\n IERC20 token = IERC20(_addr);\n // Remove Uniswap approval\n token.safeApprove(uniswapAddr, 0);\n }\n\n emit SwapTokenRemoved(_addr);\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 }\n // Tell new Strategy to deposit into protocol\n strategyTo.depositAll();\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 * @dev Sets the trusteeAddress that can receive a portion of yield.\n * Setting to the zero address disables this feature.\n */\n function setTrusteeAddress(address _address) external onlyGovernor {\n trusteeAddress = _address;\n emit TrusteeAddressChanged(_address);\n }\n\n /**\n * @dev Sets the TrusteeFeeBps to the percentage of yield that should be\n * received in basis points.\n */\n function setTrusteeFeeBps(uint256 _basis) external onlyGovernor {\n require(_basis <= 5000, \"basis cannot exceed 50%\");\n trusteeFeeBps = _basis;\n emit TrusteeFeeBpsChanged(_basis);\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 onlyGovernorOrStrategist {\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 require(!assets[_asset].isSupported, \"Only unsupported assets\");\n IERC20(_asset).safeTransfer(governor(), _amount);\n }\n\n /**\n * @dev Collect reward tokens from all strategies\n */\n function harvest() public onlyGovernorOrStrategist {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n _harvest(allStrategies[i]);\n }\n }\n\n /**\n * @dev Swap all supported swap tokens for stablecoins via Uniswap.\n */\n function swap() external onlyVaultOrGovernorOrStrategist {\n _swap();\n }\n\n /*\n * @dev Collect reward tokens from all strategies and swap for supported\n * stablecoin via Uniswap\n */\n function harvestAndSwap() external onlyGovernorOrStrategist {\n harvest();\n _swap();\n }\n\n /**\n * @dev Collect reward tokens for a specific strategy. Called from the vault.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvest(address _strategyAddr)\n external\n onlyVaultOrGovernorOrStrategist\n {\n _harvest(_strategyAddr);\n }\n\n /**\n * @dev Collect reward tokens for a specific strategy and swap for supported\n * stablecoin via Uniswap. Called from the vault.\n * @param _strategyAddr Address of the strategy to collect rewards from\n */\n function harvestAndSwap(address _strategyAddr)\n external\n onlyVaultOrGovernorOrStrategist\n returns (uint256[] memory)\n {\n IStrategy strategy = IStrategy(_strategyAddr);\n _harvest(address(strategy));\n return _swap(strategy.rewardTokenAddress());\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) internal {\n IStrategy strategy = IStrategy(_strategyAddr);\n address rewardTokenAddress = strategy.rewardTokenAddress();\n if (rewardTokenAddress != address(0)) {\n strategy.collectRewardToken();\n }\n }\n\n /**\n * @dev Swap all supported swap tokens for stablecoins via Uniswap.\n */\n function _swap() internal {\n for (uint256 i = 0; i < swapTokens.length; i++) {\n _swap(swapTokens[i]);\n }\n }\n\n /**\n * @dev Swap a record token for stablecoins for Uniswap. The token must have\n * a registered price feed with the price provider.\n * @param _swapToken Address of the token to swap.\n */\n function _swap(address _swapToken)\n internal\n returns (uint256[] memory swapResult)\n {\n if (uniswapAddr != address(0)) {\n IERC20 swapToken = IERC20(_swapToken);\n uint256 balance = swapToken.balanceOf(address(this));\n if (balance > 0) {\n // This'll revert if there is no price feed\n uint256 oraclePrice = IOracle(priceProvider).price(_swapToken);\n // Oracle price is 1e8, USDT output is 1e6\n uint256 minExpected = ((balance * oraclePrice * 97) / 100)\n .scaleBy(6, Helpers.getDecimals(_swapToken) + 8);\n\n // Uniswap redemption path\n address[] memory path = new address[](3);\n path[0] = _swapToken;\n path[1] = IUniswapV2Router(uniswapAddr).WETH();\n path[2] = allAssets[1]; // USDT\n\n swapResult = IUniswapV2Router(uniswapAddr)\n .swapExactTokensForTokens(\n balance,\n minExpected,\n path,\n address(this),\n block.timestamp\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 * Never goes above 1, since that is how we price mints\n * @param asset address of the asset\n * @return uint256 USD price of 1 of the asset, in 18 decimal fixed\n */\n function priceUSDMint(address asset) external view returns (uint256) {\n uint256 price = IOracle(priceProvider).price(asset);\n if (price > 1e8) {\n price = 1e8;\n }\n // Price from Oracle is returned with 8 decimals so scale to 18\n return price.scaleBy(18, 8);\n }\n\n /**\n * @dev Returns the total price in 18 digit USD for a given asset.\n * Never goes below 1, since that is how we price redeems\n * @param asset Address of the asset\n * @return uint256 USD price of 1 of the asset, in 18 decimal fixed\n */\n function priceUSDRedeem(address asset) external view returns (uint256) {\n uint256 price = IOracle(priceProvider).price(asset);\n if (price < 1e8) {\n price = 1e8;\n }\n // Price from Oracle is returned with 8 decimals so scale to 18\n return price.scaleBy(18, 8);\n }\n\n /***************************************\n Strategies Admin\n ****************************************/\n\n /**\n * @dev Withdraws all assets from the strategy and sends assets to the Vault.\n * @param _strategyAddr Strategy address.\n */\n function withdrawAllFromStrategy(address _strategyAddr)\n external\n onlyGovernorOrStrategist\n {\n require(\n strategies[_strategyAddr].isSupported,\n \"Strategy is not supported\"\n );\n IStrategy strategy = IStrategy(_strategyAddr);\n strategy.withdrawAll();\n }\n\n /**\n * @dev Withdraws all assets from all the strategies and sends assets to the Vault.\n */\n function withdrawAllFromStrategies() external onlyGovernorOrStrategist {\n for (uint256 i = 0; i < allStrategies.length; i++) {\n IStrategy strategy = IStrategy(allStrategies[i]);\n strategy.withdrawAll();\n }\n }\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IOracle {\n /**\n * @dev returns the asset price in USD, 8 decimal digits.\n */\n function price(address asset) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/uniswap/IUniswapV2Router02.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/vault/VaultStorage.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.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 { Initializable } from \"../utils/Initializable.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 AssetAllocated(address _asset, address _strategy, uint256 _amount);\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 event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\n event SwapTokenAdded(address _address);\n event SwapTokenRemoved(address _address);\n\n // Assets supported by the Vault, i.e. Stablecoins\n struct Asset {\n bool isSupported;\n }\n mapping(address => Asset) internal assets;\n address[] internal 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) internal strategies;\n address[] internal 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 internal oUSD;\n\n //keccak256(\"OUSD.vault.governor.admin.impl\");\n bytes32 constant adminImplPosition =\n 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 // Trustee contract that can collect a percentage of yield\n address public trusteeAddress;\n\n // Amount of yield collected in basis points\n uint256 public trusteeFeeBps;\n\n // Tokens that should be swapped for stablecoins\n address[] public swapTokens;\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 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 Deposit the entire balance of all supported assets in the Strategy\n * to the platform\n */\n function depositAll() 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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/utils/math/SafeMath.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { InitializableERC20Detailed } 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 TotalSupplyUpdatedHighres(\n uint256 totalSupply,\n uint256 rebasingCredits,\n uint256 rebasingCreditsPerToken\n );\n\n enum RebaseOptions {\n NotSet,\n OptOut,\n OptIn\n }\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 private _rebasingCredits;\n uint256 private _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 mapping(address => uint256) public isUpgraded;\n\n uint256 private constant RESOLUTION_INCREASE = 1e9;\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 Vault 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 override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @return Low resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerToken() public view returns (uint256) {\n return _rebasingCreditsPerToken / RESOLUTION_INCREASE;\n }\n\n /**\n * @return Low resolution total number of rebasing credits\n */\n function rebasingCredits() public view returns (uint256) {\n return _rebasingCredits / RESOLUTION_INCREASE;\n }\n\n /**\n * @return High resolution rebasingCreditsPerToken\n */\n function rebasingCreditsPerTokenHighres() public view returns (uint256) {\n return _rebasingCreditsPerToken;\n }\n\n /**\n * @return High resolution total number of rebasing credits\n */\n function rebasingCreditsHighres() public view returns (uint256) {\n return _rebasingCredits;\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)\n public\n view\n override\n returns (uint256)\n {\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 * @dev Backwards compatible with old low res credits per token.\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 uint256 cpt = _creditsPerToken(_account);\n if (cpt == 1e27) {\n // For a period before the resolution upgrade, we created all new\n // contract accounts at high resolution. Since they are not changing\n // as a result of this upgrade, we will return their true values\n return (_creditBalances[_account], cpt);\n } else {\n return (\n _creditBalances[_account] / RESOLUTION_INCREASE,\n cpt / RESOLUTION_INCREASE\n );\n }\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, bool) Credit balance, credits per token of the\n * address, and isUpgraded\n */\n function creditsBalanceOfHighres(address _account)\n public\n view\n returns (\n uint256,\n uint256,\n bool\n )\n {\n return (\n _creditBalances[_account],\n _creditsPerToken(_account),\n isUpgraded[_account] == 1\n );\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)\n public\n override\n returns (bool)\n {\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 override 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 _owner has allowed to\n * `_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 override\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\n * on behalf of msg.sender. This method is included for ERC20\n * compatibility. `increaseAllowance` and `decreaseAllowance` should be\n * used instead.\n *\n * Changing an allowance with this method brings the risk that someone\n * may transfer both the old and the new allowance - if they are both\n * greater than zero - if a transfer transaction is mined before the\n * later approve() call is mined.\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)\n public\n override\n returns (bool)\n {\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\n * `_spender`.\n * This method should be used instead of approve() to avoid the double\n * approval vulnerability 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\n `_spender`.\n * @param _spender The address which will spend the funds.\n * @param _subtractedValue The amount of tokens to decrease the allowance\n * 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 _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 _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 if (_amount == 0) {\n return;\n }\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 account using rebasing accounting or non-rebasing accounting?\n * Also, ensure contracts are non-rebasing if they have not opted in.\n * @param _account Address of the account.\n */\n function _isNonRebasingAccount(address _account) internal returns (bool) {\n bool isContract = Address.isContract(_account);\n if (isContract && rebaseState[_account] == RebaseOptions.NotSet) {\n _ensureRebasingMigration(_account);\n }\n return nonRebasingCreditsPerToken[_account] > 0;\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 if (_creditBalances[_account] == 0) {\n // Since there is no existing balance, we can directly set to\n // high resolution, and do not have to do any other bookkeeping\n nonRebasingCreditsPerToken[_account] = 1e27;\n } else {\n // Migrate an existing account:\n\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(\n _creditBalances[_account]\n );\n }\n }\n }\n\n /**\n * @dev Add a contract address to the non-rebasing exception list. The\n * address's balance will be part of rebases and 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 Explicitly mark that an address is non-rebasing.\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 */\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 TotalSupplyUpdatedHighres(\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 TotalSupplyUpdatedHighres(\n _totalSupply,\n _rebasingCredits,\n _rebasingCreditsPerToken\n );\n }\n}\n" + }, + "contracts/utils/Helpers.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/utils/InitializableERC20Detailed.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 */\nabstract contract InitializableERC20Detailed is IERC20 {\n // Storage gap to skip storage from prior to OUSD reset\n uint256[100] private _____gap;\n\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 * @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/interfaces/IBasicToken.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/vault/VaultInitializer.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/MockVault.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { VaultCore } from \"../vault/VaultCore.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { VaultInitializer } from \"../vault/VaultInitializer.sol\";\nimport \"../utils/Helpers.sol\";\n\ncontract MockVault is VaultCore, VaultInitializer {\n using StableMath for uint256;\n\n uint256 storedTotalValue;\n\n function setTotalValue(uint256 _value) public {\n storedTotalValue = _value;\n }\n\n function totalValue() external view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _totalValue() internal view override returns (uint256) {\n return storedTotalValue;\n }\n\n function _checkBalance(address _asset)\n internal\n view\n override\n returns (uint256 balance)\n {\n // Avoids rounding errors by returning the total value\n // in a single currency\n if (allAssets[0] == _asset) {\n uint256 decimals = Helpers.getDecimals(_asset);\n return storedTotalValue.scaleBy(decimals, 18);\n } else {\n return 0;\n }\n }\n\n function setMaxSupplyDiff(uint256 _maxSupplyDiff) external onlyGovernor {\n maxSupplyDiff = _maxSupplyDiff;\n }\n}\n" + }, + "contracts/vault/VaultCore.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 from yield bearing strategies which will modify the supply\n of OUSD.\n * @author Origin Protocol Inc\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IBuyback } from \"../interfaces/IBuyback.sol\";\nimport \"./VaultStorage.sol\";\n\ncontract VaultCore is VaultStorage {\n using SafeERC20 for IERC20;\n using StableMath for uint256;\n using SafeMath for uint256;\n\n uint256 constant MAX_UINT =\n 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 = IOracle(priceProvider).price(_asset);\n if (price > 1e8) {\n price = 1e8;\n }\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n // Scale up to 18 decimal\n uint256 unitAdjustedDeposit = _amount.scaleBy(18, assetDecimals);\n uint256 priceAdjustedDeposit = _amount.mulTruncateScale(\n price.scaleBy(18, 8), // Oracles have 8 decimal 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 // In memoriam\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 external\n whenNotCapitalPaused\n nonReentrant\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 // Calculate redemption outputs\n (\n uint256[] memory outputs,\n uint256 _backingValue\n ) = _calculateRedeemOutputs(_amount);\n\n // Check that OUSD is backed by enough assets\n uint256 _totalSupply = oUSD.totalSupply();\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 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 // 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(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 _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() external 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 // Harvest for all reward tokens above reward liquidation threshold.\n // Harvesting is the first action that takes place so we have an up to\n // date picture of total assets before allocating to strategies.\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)).harvestAndSwap(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)).harvestAndSwap(allStrategies[i]);\n }\n }\n }\n }\n\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 to 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[\n address(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 emit AssetAllocated(\n address(asset),\n depositStrategyAddr,\n allocateAmount\n );\n }\n }\n\n // Trigger OGN Buyback\n address _trusteeAddress = trusteeAddress; // gas savings\n if (_trusteeAddress != address(0)) {\n IBuyback(trusteeAddress).swap();\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 */\n function rebase() external virtual nonReentrant {\n _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, optionally sending a\n * portion of the yield to the trustee.\n */\n function _rebase() internal whenNotRebasePaused {\n uint256 ousdSupply = oUSD.totalSupply();\n if (ousdSupply == 0) {\n return;\n }\n uint256 vaultValue = _totalValue();\n\n // Yield fee collection\n address _trusteeAddress = trusteeAddress; // gas savings\n if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) {\n uint256 yield = vaultValue.sub(ousdSupply);\n uint256 fee = yield.mul(trusteeFeeBps).div(10000);\n require(yield > fee, \"Fee must not be greater than yield\");\n if (fee > 0) {\n oUSD.mint(_trusteeAddress, fee);\n }\n emit YieldDistribution(_trusteeAddress, yield, fee);\n }\n\n // Only rachet OUSD supply upwards\n ousdSupply = oUSD.totalSupply(); // Final check should use latest value\n if (vaultValue > ousdSupply) {\n oUSD.changeSupply(vaultValue);\n }\n }\n\n /**\n * @dev Determine the total value of assets held by the vault and its\n * strategies.\n * @return value Total value in USD (1e18)\n */\n function totalValue() external view virtual 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 value Total value in USD (1e18)\n */\n function _totalValue() internal view virtual 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 value 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(18, assetDecimals));\n }\n }\n }\n\n /**\n * @dev Internal to calculate total value of all assets held in Strategies.\n * @return value 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 value 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(balance.scaleBy(18, assetDecimals));\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 balance Balance of asset in decimals of asset\n */\n function _checkBalance(address _asset)\n internal\n view\n virtual\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 balance 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(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 (uint256[] memory outputs, ) = _calculateRedeemOutputs(_amount);\n return outputs;\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 outputs Array of amounts respective to the supported assets\n * @return totalBalance Total balance of Vault\n */\n function _calculateRedeemOutputs(uint256 _amount)\n internal\n view\n returns (uint256[] memory outputs, uint256 totalBalance)\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();\n uint256[] memory assetBalances = new uint256[](assetCount);\n uint256[] memory assetDecimals = new uint256[](assetCount);\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(balance.scaleBy(18, decimals));\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(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 assetPrices Array of asset prices in USD (1e18)\n */\n function _getAssetPrices()\n internal\n view\n returns (uint256[] memory assetPrices)\n {\n assetPrices = new uint256[](getAssetCount());\n\n IOracle oracle = IOracle(priceProvider);\n // Price from Oracle is returned with 8 decimals\n // _amount is in assetDecimals\n for (uint256 i = 0; i < allAssets.length; i++) {\n assetPrices[i] = oracle.price(allAssets[i]).scaleBy(18, 8);\n }\n }\n\n /***************************************\n Utils\n ****************************************/\n\n /**\n * @dev Return the number of assets supported 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 fallback() 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(\n gas(),\n sload(slot),\n 0,\n calldatasize(),\n 0,\n 0\n )\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/interfaces/IVault.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IVault {\n event AssetSupported(address _asset);\n event AssetDefaultStrategyUpdated(address _asset, address _strategy);\n event AssetAllocated(address _asset, address _strategy, uint256 _amount);\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 event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n event TrusteeFeeBpsChanged(uint256 _basis);\n event TrusteeAddressChanged(address _address);\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 setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n function maxSupplyDiff() external view returns (uint256);\n\n function setTrusteeAddress(address _address) external;\n\n function trusteeAddress() external view returns (address);\n\n function setTrusteeFeeBps(uint256 _basis) external;\n\n function trusteeFeeBps() external view returns (uint256);\n\n function supportAsset(address _asset) external;\n\n function approveStrategy(address _addr) external;\n\n function removeStrategy(address _addr) external;\n\n function addSwapToken(address _addr) external;\n\n function removeSwapToken(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 harvestAndSwap() external;\n\n function harvest(address _strategyAddr) external;\n\n function harvestAndSwap(address _strategyAddr) external;\n\n function swap() external;\n\n function priceUSDMint(address asset) external view returns (uint256);\n\n function priceUSDRedeem(address asset) external view returns (uint256);\n\n function withdrawAllFromStrategy(address _strategyAddr) external;\n\n function withdrawAllFromStrategies() external;\n\n function reallocate(\n address _strategyFromAddress,\n address _strategyToAddress,\n address[] calldata _assets,\n uint256[] calldata _amounts\n ) external;\n\n // VaultCore.sol\n function mint(\n address _asset,\n uint256 _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 rebase() external;\n\n function totalValue() external view returns (uint256 value);\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/interfaces/IBuyback.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IBuyback {\n function swap() external;\n}\n" + }, + "contracts/strategies/ThreePoolStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurveGauge } from \"./ICurveGauge.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport { IERC20, BaseCurveStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\ncontract ThreePoolStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n address internal crvGaugeAddress;\n address internal crvMinterAddress;\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 _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\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[] calldata _assets,\n address[] calldata _pTokens,\n address _crvGaugeAddress,\n address _crvMinterAddress\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n crvGaugeAddress = _crvGaugeAddress;\n crvMinterAddress = _crvMinterAddress;\n pTokenAddress = _pTokens[0];\n super._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit into Gauge\n ICurveGauge(crvGaugeAddress).deposit(\n pToken.balanceOf(address(this)),\n address(this)\n );\n }\n\n function _lpWithdraw(uint256 numPTokens) internal override {\n // Not enough of pool token exists on this contract, some must be\n // staked in Gauge, unstake difference\n ICurveGauge(crvGaugeAddress).withdraw(numPTokens);\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 contractPTokens Amount of platform tokens in this contract\n * @return gaugePTokens Amount of platform tokens staked in gauge\n * @return totalPTokens Total amount of platform tokens in native decimals\n */\n function _getTotalPTokens()\n internal\n view\n override\n returns (\n uint256 contractPTokens,\n uint256 gaugePTokens,\n uint256 totalPTokens\n )\n {\n contractPTokens = IERC20(pTokenAddress).balanceOf(address(this));\n ICurveGauge gauge = ICurveGauge(crvGaugeAddress);\n gaugePTokens = gauge.balanceOf(address(this));\n totalPTokens = contractPTokens + gaugePTokens;\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(crvGaugeAddress, 0);\n pToken.safeApprove(crvGaugeAddress, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated CRV and send to Vault.\n */\n function collectRewardToken() external override onlyVault nonReentrant {\n // Collect\n ICRVMinter(crvMinterAddress).mint(crvGaugeAddress);\n // Send\n IERC20 crvToken = IERC20(rewardTokenAddress);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, balance);\n crvToken.safeTransfer(vaultAddress, balance);\n }\n}\n" + }, + "contracts/strategies/ICurveGauge.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface ICRVMinter {\n function mint(address gaugeAddress) external;\n}\n" + }, + "contracts/strategies/BaseCurveStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title Curve 3Pool Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { ICurvePool } from \"./ICurvePool.sol\";\nimport { ICRVMinter } from \"./ICRVMinter.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract BaseCurveStrategy is InitializableAbstractStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 internal constant maxSlippage = 1e16; // 1%, same as the Curve UI\n address internal pTokenAddress;\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 override\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 uint256 poolCoinIndex = _getCoinIndex(_asset);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = _amount;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n uint256 depositValue = _amount.scaleBy(18, assetDecimals).divPrecisely(\n curvePool.get_virtual_price()\n );\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n _lpDepositAll();\n }\n\n function _lpDepositAll() internal virtual;\n\n /**\n * @dev Deposit the entire balance of any supported asset into the Curve 3pool\n */\n function depositAll() external override onlyVault nonReentrant {\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n uint256 depositValue = 0;\n ICurvePool curvePool = ICurvePool(platformAddress);\n uint256 curveVirtualPrice = curvePool.get_virtual_price();\n\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address assetAddress = assetsMapped[i];\n uint256 balance = IERC20(assetAddress).balanceOf(address(this));\n if (balance > 0) {\n uint256 poolCoinIndex = _getCoinIndex(assetAddress);\n // Set the amount on the asset we want to deposit\n _amounts[poolCoinIndex] = balance;\n uint256 assetDecimals = Helpers.getDecimals(assetAddress);\n // Get value of deposit in Curve LP token to later determine\n // the minMintAmount argument for add_liquidity\n depositValue =\n depositValue +\n balance.scaleBy(18, assetDecimals).divPrecisely(\n curveVirtualPrice\n );\n emit Deposit(assetAddress, address(platformAddress), balance);\n }\n }\n\n uint256 minMintAmount = depositValue.mulTruncate(\n uint256(1e18) - maxSlippage\n );\n // Do the deposit to 3pool\n curvePool.add_liquidity(_amounts, minMintAmount);\n // Deposit into Gauge, the PToken is the same (3Crv) for all mapped\n // assets, so just get the address from the first one\n _lpDepositAll();\n }\n\n function _lpWithdraw(uint256 numPTokens) internal virtual;\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 override onlyVault nonReentrant {\n require(_amount > 0, \"Invalid amount\");\n\n emit Withdrawal(_asset, address(assetToPToken[_asset]), _amount);\n\n (uint256 contractPTokens, , uint256 totalPTokens) = _getTotalPTokens();\n\n uint256 coinIndex = _getCoinIndex(_asset);\n int128 curveCoinIndex = int128(uint128(coinIndex));\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 // Calculate how many platform tokens we need to withdraw the asset\n // amount in the worst case (i.e withdrawing all LP tokens)\n uint256 maxAmount = curvePool.calc_withdraw_one_coin(\n totalPTokens,\n curveCoinIndex\n );\n uint256 maxBurnedPTokens = (totalPTokens * _amount) / maxAmount;\n\n // Not enough in this contract or in the Gauge, can't proceed\n require(totalPTokens > maxBurnedPTokens, \"Insufficient 3CRV balance\");\n // We have enough LP tokens, make sure they are all on this contract\n if (contractPTokens < maxBurnedPTokens) {\n _lpWithdraw(maxBurnedPTokens - contractPTokens);\n }\n\n uint256[3] memory _amounts = [uint256(0), uint256(0), uint256(0)];\n _amounts[coinIndex] = _amount;\n curvePool.remove_liquidity_imbalance(_amounts, maxBurnedPTokens);\n\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 override onlyVaultOrGovernor nonReentrant {\n // Withdraw all from Gauge\n (, uint256 gaugePTokens, uint256 totalPTokens) = _getTotalPTokens();\n _lpWithdraw(gaugePTokens);\n // Withdraws are proportional to assets held by 3Pool\n uint256[3] memory minWithdrawAmounts = [\n uint256(0),\n uint256(0),\n uint256(0)\n ];\n // Remove liquidity\n ICurvePool threePool = ICurvePool(platformAddress);\n threePool.remove_liquidity(totalPTokens, minWithdrawAmounts);\n // Transfer assets out of Vault\n // Note that Curve will provide all 3 of the assets in 3pool even if\n // we have not set PToken addresses for all of them in this strategy\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n IERC20 asset = IERC20(threePool.coins(i));\n asset.safeTransfer(vaultAddress, asset.balanceOf(address(this)));\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 public\n view\n override\n returns (uint256 balance)\n {\n require(assetToPToken[_asset] != address(0), \"Unsupported asset\");\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 ICurvePool curvePool = ICurvePool(platformAddress);\n if (totalPTokens > 0) {\n uint256 virtual_price = curvePool.get_virtual_price();\n uint256 value = (totalPTokens * virtual_price) / 1e18;\n uint256 assetDecimals = Helpers.getDecimals(_asset);\n balance = value.scaleBy(assetDecimals, 18) / 3;\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)\n external\n view\n override\n returns (bool)\n {\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()\n external\n override\n onlyGovernor\n nonReentrant\n {\n _approveBase();\n // This strategy is a special case since it only supports one asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n _approveAsset(assetsMapped[i]);\n }\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 contractPTokens Amount of platform tokens in this contract\n * @return gaugePTokens Amount of platform tokens staked in gauge\n * @return totalPTokens Total amount of platform tokens in native decimals\n */\n function _getTotalPTokens()\n internal\n view\n virtual\n returns (\n uint256 contractPTokens,\n uint256 gaugePTokens,\n uint256 totalPTokens\n );\n\n /**\n * @dev Call the necessary approvals for the Curve pool and gauge\n * @param _asset Address of the asset\n */\n function _abstractSetPToken(address _asset, address _pToken)\n internal\n override\n {\n _approveAsset(_asset);\n }\n\n function _approveAsset(address _asset) internal {\n IERC20 asset = IERC20(_asset);\n // 3Pool for asset (required for adding liquidity)\n asset.safeApprove(platformAddress, 0);\n asset.safeApprove(platformAddress, type(uint256).max);\n }\n\n function _approveBase() internal virtual;\n\n /**\n * @dev Get the index of the coin\n */\n function _getCoinIndex(address _asset) internal view returns (uint256) {\n for (uint256 i = 0; i < 3; i++) {\n if (assetsMapped[i] == _asset) return i;\n }\n revert(\"Invalid 3pool asset\");\n }\n}\n" + }, + "contracts/strategies/ICurvePool.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface ICurvePool {\n function get_virtual_price() external view returns (uint256);\n\n function add_liquidity(uint256[3] calldata _amounts, uint256 _min) external;\n\n function balances(uint256) external view returns (uint256);\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 remove_liquidity(\n uint256 _amount,\n uint256[3] calldata _minWithdrawAmounts\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 function remove_liquidity_imbalance(\n uint256[3] calldata _amounts,\n uint256 maxBurnAmount\n ) external;\n}\n" + }, + "contracts/strategies/ConvexStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title Curve Convex Strategy\n * @notice Investment strategy for investing stablecoins via Curve 3Pool\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IRewardStaking } from \"./IRewardStaking.sol\";\nimport { IConvexDeposits } from \"./IConvexDeposits.sol\";\nimport { IERC20, BaseCurveStrategy } from \"./BaseCurveStrategy.sol\";\nimport { StableMath } from \"../utils/StableMath.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\ncontract ConvexStrategy is BaseCurveStrategy {\n using StableMath for uint256;\n using SafeERC20 for IERC20;\n\n event RewardTokenCollected(\n address recipient,\n address token,\n uint256 amount\n );\n\n event CvxRewardTokenAddressUpdated(\n address _oldAddress,\n address _newAddress\n );\n\n address internal cvxDepositorAddress;\n address internal cvxRewardStakerAddress;\n address public cvxRewardTokenAddress;\n uint256 internal cvxDepositorPTokenId;\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 _cvxRewardTokenAddress Address of CVX *yes we get both*\n * @param _assets Addresses of supported assets. MUST be passed in the same\n * order as returned by coins on the pool contract, i.e.\n * DAI, USDC, USDT\n * @param _pTokens Platform Token corresponding addresses\n * @param _cvxDepositorAddress Address of the Convex depositor(AKA booster) for this pool\n * @param _cvxRewardStakerAddress Address of the CVX rewards staker\n * @param _cvxDepositorPTokenId Pid of the pool referred to by Depositor and staker\n */\n function initialize(\n address _platformAddress, // 3Pool address\n address _vaultAddress,\n address _rewardTokenAddress, // CRV\n address _cvxRewardTokenAddress, // CVX\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _cvxDepositorAddress,\n address _cvxRewardStakerAddress,\n uint256 _cvxDepositorPTokenId\n ) external onlyGovernor initializer {\n require(_assets.length == 3, \"Must have exactly three assets\");\n // Should be set prior to abstract initialize call otherwise\n // abstractSetPToken calls will fail\n cvxDepositorAddress = _cvxDepositorAddress;\n cvxRewardStakerAddress = _cvxRewardStakerAddress;\n cvxDepositorPTokenId = _cvxDepositorPTokenId;\n cvxRewardTokenAddress = _cvxRewardTokenAddress;\n pTokenAddress = _pTokens[0];\n super._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n _approveBase();\n }\n\n /**\n * @dev Set the CVX reward token address.\n * @param _cvxRewardTokenAddress Address of the reward token\n */\n function setCvxRewardTokenAddress(address _cvxRewardTokenAddress)\n external\n onlyGovernor\n {\n emit CvxRewardTokenAddressUpdated(\n cvxRewardTokenAddress,\n _cvxRewardTokenAddress\n );\n cvxRewardTokenAddress = _cvxRewardTokenAddress;\n }\n\n function _lpDepositAll() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // Deposit with staking\n bool success = IConvexDeposits(cvxDepositorAddress).deposit(\n cvxDepositorPTokenId,\n pToken.balanceOf(address(this)),\n true\n );\n require(success, \"Failed to deposit to Convex\");\n }\n\n function _lpWithdraw(uint256 numPTokens) internal override {\n // withdraw and unwrap with claim takes back the lpTokens and also collects the rewards to this\n IRewardStaking(cvxRewardStakerAddress).withdrawAndUnwrap(\n numPTokens,\n true\n );\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 contractPTokens Amount of platform tokens in this contract\n * @return gaugePTokens Amount of platform tokens staked in gauge\n * @return totalPTokens Total amount of platform tokens in native decimals\n */\n function _getTotalPTokens()\n internal\n view\n override\n returns (\n uint256 contractPTokens,\n uint256 gaugePTokens, // gauge is a misnomer here, need a better name\n uint256 totalPTokens\n )\n {\n contractPTokens = IERC20(pTokenAddress).balanceOf(address(this));\n gaugePTokens = IRewardStaking(cvxRewardStakerAddress).balanceOf(\n address(this)\n ); //booster.poolInfo[pid].token.balanceOf(address(this)) Not needed if we always stake..\n totalPTokens = contractPTokens + gaugePTokens;\n }\n\n function _approveBase() internal override {\n IERC20 pToken = IERC20(pTokenAddress);\n // 3Pool for LP token (required for removing liquidity)\n pToken.safeApprove(platformAddress, 0);\n pToken.safeApprove(platformAddress, type(uint256).max);\n // Gauge for LP token\n pToken.safeApprove(cvxDepositorAddress, 0);\n pToken.safeApprove(cvxDepositorAddress, type(uint256).max);\n }\n\n /**\n * @dev Collect accumulated CRV and CVX and send to Vault.\n */\n function collectRewardToken() external override onlyVault nonReentrant {\n // Collect CRV and CVX\n IRewardStaking(cvxRewardStakerAddress).getReward();\n // Send CRV\n IERC20 crvToken = IERC20(rewardTokenAddress);\n uint256 balance = crvToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, rewardTokenAddress, balance);\n crvToken.safeTransfer(vaultAddress, balance);\n // Send CVX\n IERC20 cvxToken = IERC20(cvxRewardTokenAddress);\n balance = cvxToken.balanceOf(address(this));\n emit RewardTokenCollected(vaultAddress, cvxRewardTokenAddress, balance);\n cvxToken.safeTransfer(vaultAddress, balance);\n }\n}\n" + }, + "contracts/strategies/IRewardStaking.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IRewardStaking {\n function stakeFor(address, uint256) external;\n\n function stake(uint256) external;\n\n function withdraw(uint256 amount, bool claim) external;\n\n function withdrawAndUnwrap(uint256 amount, bool claim) external;\n\n function earned(address account) external view returns (uint256);\n\n function getReward() external;\n\n function getReward(address _account, bool _claimExtras) external;\n\n function extraRewardsLength() external returns (uint256);\n\n function extraRewards(uint256 _pid) external returns (address);\n\n function rewardToken() external returns (address);\n\n function balanceOf(address account) external view returns (uint256);\n}\n" + }, + "contracts/strategies/IConvexDeposits.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IConvexDeposits {\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) external returns (bool);\n\n function deposit(\n uint256 _amount,\n bool _lock,\n address _stakeAddress\n ) external;\n}\n" + }, + "contracts/mocks/curve/MockBooster.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MockRewardPool } from \"./MockRewardPool.sol\";\n\nimport { IRewardStaking } from \"../../strategies/IRewardStaking.sol\";\nimport { IMintableERC20, MintableERC20, ERC20 } from \"../MintableERC20.sol\";\nimport { IBurnableERC20, BurnableERC20 } from \"../BurnableERC20.sol\";\n\ncontract MockDepositToken is MintableERC20 {\n constructor() ERC20(\"DCVX\", \"CVX Deposit Token\") {}\n}\n\ncontract MockBooster {\n using SafeERC20 for IERC20;\n\n struct PoolInfo {\n address lptoken;\n address token;\n address crvRewards;\n }\n\n address public minter; // this is CVx for the booster on live\n address public crv; // Curve rewards token\n address public cvx; // Convex rewards token\n mapping(uint256 => PoolInfo) public poolInfo;\n\n constructor(\n address _rewardsMinter,\n address _crv,\n address _cvx\n ) public {\n minter = _rewardsMinter;\n crv = _crv;\n cvx = _cvx;\n }\n\n function setPool(uint256 pid, address _lpToken) external returns (bool) {\n address token = address(new MockDepositToken());\n address rewards = address(\n new MockRewardPool(pid, token, crv, cvx, address(this))\n );\n\n poolInfo[pid] = PoolInfo({\n lptoken: _lpToken,\n token: token,\n crvRewards: rewards\n });\n }\n\n function deposit(\n uint256 _pid,\n uint256 _amount,\n bool _stake\n ) public returns (bool) {\n PoolInfo storage pool = poolInfo[_pid];\n\n address lptoken = pool.lptoken;\n\n // hold on to the lptokens\n IERC20(lptoken).safeTransferFrom(msg.sender, address(this), _amount);\n\n address token = pool.token;\n if (_stake) {\n //mint here and send to rewards on user behalf\n IMintableERC20(token).mint(_amount);\n address rewardContract = pool.crvRewards;\n IERC20(token).safeApprove(rewardContract, 0);\n IERC20(token).safeApprove(rewardContract, _amount);\n IRewardStaking(rewardContract).stakeFor(msg.sender, _amount);\n } else {\n //add user balance directly\n IMintableERC20(token).mint(_amount);\n IERC20(token).transfer(msg.sender, _amount);\n }\n return true;\n }\n\n //deposit all lp tokens and stake\n function depositAll(uint256 _pid, bool _stake) external returns (bool) {\n address lptoken = poolInfo[_pid].lptoken;\n uint256 balance = IERC20(lptoken).balanceOf(msg.sender);\n deposit(_pid, balance, _stake);\n return true;\n }\n\n //withdraw lp tokens\n function _withdraw(\n uint256 _pid,\n uint256 _amount,\n address _from,\n address _to\n ) internal {\n PoolInfo storage pool = poolInfo[_pid];\n address lptoken = pool.lptoken;\n address token = pool.token;\n\n //remove lp balance\n IBurnableERC20(token).burnFrom(_from, _amount);\n\n //return lp tokens\n IERC20(lptoken).safeTransfer(_to, _amount);\n }\n\n //withdraw lp tokens\n function withdraw(uint256 _pid, uint256 _amount) public returns (bool) {\n _withdraw(_pid, _amount, msg.sender, msg.sender);\n return true;\n }\n\n //withdraw all lp tokens\n function withdrawAll(uint256 _pid) public returns (bool) {\n address token = poolInfo[_pid].token;\n uint256 userBal = IERC20(token).balanceOf(msg.sender);\n withdraw(_pid, userBal);\n return true;\n }\n\n //allow reward contracts to send here and withdraw to user\n function withdrawTo(\n uint256 _pid,\n uint256 _amount,\n address _to\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n _withdraw(_pid, _amount, msg.sender, _to);\n return true;\n }\n\n //callback from reward contract when crv is received.\n function rewardClaimed(\n uint256 _pid,\n address _address,\n uint256 _amount\n ) external returns (bool) {\n address rewardContract = poolInfo[_pid].crvRewards;\n require(msg.sender == rewardContract, \"!auth\");\n\n //mint reward tokens\n // and transfer it\n IMintableERC20(minter).mint(_amount);\n IERC20(minter).transfer(msg.sender, _amount);\n return true;\n }\n}\n" + }, + "contracts/mocks/curve/MockRewardPool.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IMintableERC20 } from \"../MintableERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\ninterface IDeposit {\n function poolInfo(uint256)\n external\n view\n returns (\n address,\n address,\n address,\n address,\n address,\n bool\n );\n\n function rewardClaimed(\n uint256,\n address,\n uint256\n ) external;\n\n function withdrawTo(\n uint256,\n uint256,\n address\n ) external;\n}\n\ncontract MockRewardPool {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n uint256 public pid;\n address public stakingToken;\n address public rewardTokenA;\n address public rewardTokenB;\n address public operator;\n\n uint256 private _totalSupply;\n\n mapping(address => uint256) private _balances;\n mapping(address => uint256) public rewards;\n\n constructor(\n uint256 _pid,\n address _stakingToken,\n address _rewardTokenA,\n address _rewardTokenB,\n address _operator\n ) public {\n pid = _pid;\n stakingToken = _stakingToken;\n rewardTokenA = _rewardTokenA;\n rewardTokenB = _rewardTokenB;\n }\n\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n function stakeFor(address _for, uint256 _amount) public returns (bool) {\n require(_amount > 0, \"RewardPool : Cannot stake 0\");\n\n //give to _for\n _totalSupply = _totalSupply.add(_amount);\n _balances[_for] = _balances[_for].add(_amount);\n\n //take away from sender\n IERC20(stakingToken).safeTransferFrom(\n msg.sender,\n address(this),\n _amount\n );\n\n return true;\n }\n\n function withdrawAndUnwrap(uint256 amount, bool claim)\n public\n returns (bool)\n {\n _totalSupply = _totalSupply.sub(amount);\n _balances[msg.sender] = _balances[msg.sender].sub(amount);\n\n //tell operator to withdraw from here directly to user\n IDeposit(operator).withdrawTo(pid, amount, msg.sender);\n\n //get rewards too\n if (claim) {\n getReward(msg.sender, true);\n }\n return true;\n }\n\n function withdrawAllAndUnwrap(bool claim) external {\n withdrawAndUnwrap(_balances[msg.sender], claim);\n }\n\n function getReward(address _account, bool _claimExtras)\n public\n returns (bool)\n {\n IMintableERC20(rewardTokenA).mint(2 * 1e18);\n IERC20(rewardTokenA).transfer(_account, 2 * 1e18);\n\n IMintableERC20(rewardTokenB).mint(3 * 1e18);\n IERC20(rewardTokenB).transfer(_account, 3 * 1e18);\n\n return true;\n }\n\n function getReward() public returns (bool) {\n getReward(msg.sender, true);\n }\n}\n" + }, + "contracts/mocks/MintableERC20.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(uint256 value) external;\n\n function mintTo(address to, uint256 value) external;\n}\n\n/**\n * @title MintableERC20\n * @dev Exposes the mint function of ERC20 for tests\n */\nabstract contract MintableERC20 is IMintableERC20, ERC20 {\n /**\n * @dev Function to mint tokens\n * @param _value The amount of tokens to mint.\n */\n function mint(uint256 _value) public virtual override {\n _mint(msg.sender, _value);\n }\n\n /**\n * @dev Function to mint tokens\n * @param _to Address to mint to.\n * @param _value The amount of tokens to mint.\n */\n function mintTo(address _to, uint256 _value) public virtual override {\n _mint(_to, _value);\n }\n}\n" + }, + "contracts/mocks/BurnableERC20.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ninterface IBurnableERC20 {\n function burn(uint256 value) external returns (bool);\n\n function burnFrom(address account, uint256 value) external returns (bool);\n}\n\n/**\n * @title BurnableERC20\n * @dev Exposes the burn function of ERC20 for tests\n */\nabstract contract BurnableERC20 is IBurnableERC20, ERC20 {\n /**\n * @dev Function to burn tokens\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burn(uint256 value) public virtual override returns (bool) {\n _burn(msg.sender, value);\n return true;\n }\n\n /**\n * @dev Function to burn tokens from a specific account\n * @param account The address with the tokens to burn.\n * @param value The amount of tokens to burn.\n * @return A boolean that indicates if the operation was successful.\n */\n function burnFrom(address account, uint256 value)\n public\n override\n returns (bool)\n {\n _burn(account, value);\n return true;\n }\n}\n" + }, + "contracts/mocks/MockOGN.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./BurnableERC20.sol\";\nimport \"./MintableERC20.sol\";\n\n/**\n * @title Origin token (OGN).\n *\n * @dev Token that allows minting and burning.\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 */\ncontract MockOGN is MintableERC20, BurnableERC20 {\n event SetWhitelistExpiration(uint256 expiration);\n event AllowedTransactorAdded(address sender);\n event AllowedTransactorRemoved(address sender);\n event AddCallSpenderWhitelist(address enabler, address spender);\n event RemoveCallSpenderWhitelist(address disabler, address spender);\n\n mapping(address => bool) public callSpenderWhitelist;\n address public owner = msg.sender;\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 // @dev Constructor that gives msg.sender all initial tokens.\n constructor(uint256 _initialSupply) ERC20(\"OriginToken\", \"OGN\") {\n owner = msg.sender;\n _mint(owner, _initialSupply);\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(uint160(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 //\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 override\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 override allowedTransfer(_from, _to) returns (bool) {\n return super.transferFrom(_from, _to, _value);\n }\n}\n" + }, + "contracts/mocks/MockWETH.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockWETH is MintableERC20 {\n constructor() ERC20(\"WETH\", \"WETH\") {}\n}\n" + }, + "contracts/mocks/MockUSDT.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDT is MintableERC20 {\n constructor() ERC20(\"USDT Coin\", \"USDT\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockUSDC.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockUSDC is MintableERC20 {\n constructor() ERC20(\"USDC Coin\", \"USDC\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n}\n" + }, + "contracts/mocks/MockTUSD.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockTUSD is MintableERC20 {\n constructor() ERC20(\"TrueUSD\", \"TUSD\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockNonStandardToken.sol": { + "content": "pragma solidity ^0.8.0;\n\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\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 using SafeMath for uint256;\n\n constructor() ERC20(\"NonStandardToken\", \"NonStandardToken\") {}\n\n function decimals() public pure override returns (uint8) {\n return 6;\n }\n\n function transfer(address recipient, uint256 amount)\n public\n override\n returns (bool)\n {\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 override 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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport \"./MockUniswapPair.sol\";\n\ncontract MockMintableUniswapPair is MockUniswapPair, MintableERC20 {\n constructor(\n address _token0,\n address _token1,\n uint112 _reserve0,\n uint112 _reserve1\n )\n MockUniswapPair(_token0, _token1, _reserve0, _reserve1)\n ERC20(\"Uniswap V2\", \"UNI-v2\")\n {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/MockUniswapPair.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 ) {\n tok0 = _token0;\n tok1 = _token1;\n reserve0 = _reserve0;\n reserve1 = _reserve1;\n blockTimestampLast = block.timestamp;\n }\n\n function token0() external view override returns (address) {\n return tok0;\n }\n\n function token1() external view override returns (address) {\n return tok1;\n }\n\n function getReserves()\n external\n view\n override\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\n // multiple different blocks because then it wouldn't be a continuous\n // reserve factor over that blockTimestamp, this assumes an even reserve\n // ratio all the way through\n function price0CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n blockTimestampLast;\n }\n\n function price1CumulativeLast() external view override returns (uint256) {\n return\n uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n blockTimestampLast;\n }\n\n function sync() external override {\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\ncontract MockEvilDAI is MintableERC20 {\n address host;\n address realCoin;\n\n constructor(address _host, address _realCoin) ERC20(\"DAI\", \"DAI\") {\n host = _host;\n realCoin = _realCoin;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _amount\n ) public override 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/oracle/OracleRouter.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\nimport { IOracle } from \"../interfaces/IOracle.sol\";\nimport { Helpers } from \"../utils/Helpers.sol\";\n\nabstract contract OracleRouterBase is IOracle {\n uint256 constant MIN_DRIFT = uint256(70000000);\n uint256 constant MAX_DRIFT = uint256(130000000);\n\n /**\n * @dev The price feed contract to use for a particular asset.\n * @param asset address of the asset\n * @return address address of the price feed for the asset\n */\n function feed(address asset) internal view virtual returns (address);\n\n /**\n * @notice Returns the total price in 8 digit USD for a given asset.\n * @param asset address of the asset\n * @return uint256 USD price of 1 of the asset, in 8 decimal fixed\n */\n function price(address asset) external view override returns (uint256) {\n address _feed = feed(asset);\n require(_feed != address(0), \"Asset not available\");\n (, int256 _iprice, , , ) = AggregatorV3Interface(_feed)\n .latestRoundData();\n uint256 _price = uint256(_iprice);\n if (isStablecoin(asset)) {\n require(_price <= MAX_DRIFT, \"Oracle: Price exceeds max\");\n require(_price >= MIN_DRIFT, \"Oracle: Price under min\");\n }\n return uint256(_price);\n }\n\n function isStablecoin(address _asset) internal view returns (bool) {\n string memory symbol = Helpers.getSymbol(_asset);\n bytes32 symbolHash = keccak256(abi.encodePacked(symbol));\n return\n symbolHash == keccak256(abi.encodePacked(\"DAI\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDC\")) ||\n symbolHash == keccak256(abi.encodePacked(\"USDT\"));\n }\n}\n\ncontract OracleRouter is OracleRouterBase {\n /**\n * @dev The price feed contract to use for a particular asset.\n * @param asset address of the asset\n */\n function feed(address asset) internal pure override returns (address) {\n if (asset == address(0x6B175474E89094C44Da98b954EedeAC495271d0F)) {\n // Chainlink: DAI/USD\n return address(0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9);\n } else if (\n asset == address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)\n ) {\n // Chainlink: USDC/USD\n return address(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);\n } else if (\n asset == address(0xdAC17F958D2ee523a2206206994597C13D831ec7)\n ) {\n // Chainlink: USDT/USD\n return address(0x3E7d1eAB13ad0104d2750B8863b489D65364e32D);\n } else if (\n asset == address(0xc00e94Cb662C3520282E6f5717214004A7f26888)\n ) {\n // Chainlink: COMP/USD\n return address(0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5);\n } else if (\n asset == address(0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9)\n ) {\n // Chainlink: AAVE/USD\n return address(0x547a514d5e3769680Ce22B2361c10Ea13619e8a9);\n } else if (\n asset == address(0xD533a949740bb3306d119CC777fa900bA034cd52)\n ) {\n // Chainlink: CRV/USD\n return address(0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f);\n } else {\n revert(\"Asset not available\");\n }\n }\n}\n\ncontract OracleRouterDev is OracleRouterBase {\n mapping(address => address) public assetToFeed;\n\n function setFeed(address _asset, address _feed) external {\n assetToFeed[_asset] = _feed;\n }\n\n /**\n * @dev The price feed contract to use for a particular asset.\n * @param asset address of the asset\n */\n function feed(address asset) internal view override returns (address) {\n return assetToFeed[asset];\n }\n}\n" + }, + "contracts/mocks/MockChainlinkOracleFeed.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../interfaces/chainlink/AggregatorV3Interface.sol\";\n\ncontract MockChainlinkOracleFeed is AggregatorV3Interface {\n int256 price;\n uint8 numDecimals;\n\n constructor(int256 _price, uint8 _decimals) {\n price = _price;\n numDecimals = _decimals;\n }\n\n function decimals() external view override returns (uint8) {\n return numDecimals;\n }\n\n function description() external pure override returns (string memory) {\n return \"MockOracleEthFeed\";\n }\n\n function version() external pure override 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 override\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 override\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/strategies/AaveStrategy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Aave Strategy\n * @notice Investment strategy for investing stablecoins via Aave\n * @author Origin Protocol Inc\n */\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"./IAave.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../utils/InitializableAbstractStrategy.sol\";\n\nimport { IAaveStakedToken } from \"./IAaveStakeToken.sol\";\nimport { IAaveIncentivesController } from \"./IAaveIncentivesController.sol\";\n\ncontract AaveStrategy is InitializableAbstractStrategy {\n using SafeERC20 for IERC20;\n\n uint16 constant referralCode = 92;\n\n IAaveIncentivesController public incentivesController;\n IAaveStakedToken public stkAave;\n\n /**\n * Initializer for setting up strategy internal state. This overrides the\n * InitializableAbstractStrategy initializer as AAVE needs several extra\n * addresses for the rewards program.\n * @param _platformAddress Address of the AAVE pool\n * @param _vaultAddress Address of the vault\n * @param _rewardTokenAddress Address of the AAVE token\n * @param _assets Addresses of supported assets\n * @param _pTokens Platform Token corresponding addresses\n * @param _incentivesAddress Address of the AAVE incentives controller\n * @param _stkAaveAddress Address of the stkAave contract\n */\n function initialize(\n address _platformAddress, // AAVE pool\n address _vaultAddress,\n address _rewardTokenAddress, // AAVE\n address[] calldata _assets,\n address[] calldata _pTokens,\n address _incentivesAddress,\n address _stkAaveAddress\n ) external onlyGovernor initializer {\n incentivesController = IAaveIncentivesController(_incentivesAddress);\n stkAave = IAaveStakedToken(_stkAaveAddress);\n InitializableAbstractStrategy._initialize(\n _platformAddress,\n _vaultAddress,\n _rewardTokenAddress,\n _assets,\n _pTokens\n );\n }\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 */\n function deposit(address _asset, uint256 _amount)\n external\n override\n onlyVault\n nonReentrant\n {\n _deposit(_asset, _amount);\n }\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 */\n function _deposit(address _asset, uint256 _amount) internal {\n require(_amount > 0, \"Must deposit something\");\n // Following line also doubles as a check that we are depositing\n // an asset that we support.\n emit Deposit(_asset, _getATokenFor(_asset), _amount);\n _getLendingPool().deposit(_asset, _amount, address(this), referralCode);\n }\n\n /**\n * @dev Deposit the entire balance of any supported asset into Aave\n */\n function depositAll() external override onlyVault nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n uint256 balance = IERC20(assetsMapped[i]).balanceOf(address(this));\n if (balance > 0) {\n _deposit(assetsMapped[i], balance);\n }\n }\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 */\n function withdraw(\n address _recipient,\n address _asset,\n uint256 _amount\n ) external override onlyVault nonReentrant {\n require(_amount > 0, \"Must withdraw something\");\n require(_recipient != address(0), \"Must specify recipient\");\n\n emit Withdrawal(_asset, _getATokenFor(_asset), _amount);\n uint256 actual = _getLendingPool().withdraw(\n _asset,\n _amount,\n address(this)\n );\n require(actual == _amount, \"Did not withdraw enough\");\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 override onlyVaultOrGovernor nonReentrant {\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n // Redeem entire balance of aToken\n IERC20 asset = IERC20(assetsMapped[i]);\n address aToken = _getATokenFor(assetsMapped[i]);\n uint256 balance = IERC20(aToken).balanceOf(address(this));\n if (balance > 0) {\n uint256 actual = _getLendingPool().withdraw(\n address(asset),\n balance,\n address(this)\n );\n require(actual == balance, \"Did not withdraw enough\");\n // Transfer entire balance to Vault\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 override\n returns (uint256 balance)\n {\n // Balance is always with token aToken decimals\n address aToken = _getATokenFor(_asset);\n balance = IERC20(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)\n external\n view\n override\n returns (bool)\n {\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()\n external\n override\n onlyGovernor\n nonReentrant\n {\n address lendingPool = address(_getLendingPool());\n // approve the pool to spend the Asset\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n address asset = assetsMapped[i];\n // Safe approval\n IERC20(asset).safeApprove(lendingPool, 0);\n IERC20(asset).safeApprove(lendingPool, type(uint256).max);\n }\n }\n\n /**\n * @dev Internal method to respond to the addition of new asset / aTokens\n We need to give the AAVE lending pool approval to transfer the\n asset.\n * @param _asset Address of the asset to approve\n * @param _aToken Address of the aToken\n */\n function _abstractSetPToken(address _asset, address _aToken)\n internal\n override\n {\n address lendingPool = address(_getLendingPool());\n IERC20(_asset).safeApprove(lendingPool, 0);\n IERC20(_asset).safeApprove(lendingPool, type(uint256).max);\n }\n\n /**\n * @dev Get the aToken wrapped in the IERC20 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 (address) {\n address aToken = assetToPToken[_asset];\n require(aToken != address(0), \"aToken does not exist\");\n return 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 Collect stkAave, convert it to AAVE send to Vault.\n */\n function collectRewardToken() external override onlyVault nonReentrant {\n if (address(stkAave) == address(0)) {\n return;\n }\n\n // Check staked AAVE cooldown timer\n uint256 cooldown = stkAave.stakersCooldowns(address(this));\n uint256 windowStart = cooldown + stkAave.COOLDOWN_SECONDS();\n uint256 windowEnd = windowStart + stkAave.UNSTAKE_WINDOW();\n\n // If inside the unlock window, then we can redeem stkAave\n // for AAVE and send it to the vault.\n if (block.timestamp > windowStart && block.timestamp <= windowEnd) {\n // Redeem to AAVE\n uint256 stkAaveBalance = stkAave.balanceOf(address(this));\n if (stkAaveBalance > rewardLiquidationThreshold) {\n stkAave.redeem(address(this), stkAaveBalance);\n }\n // Transfer AAVE to vaultAddress\n uint256 aaveBalance = IERC20(rewardTokenAddress).balanceOf(\n address(this)\n );\n if (aaveBalance > 0) {\n IERC20(rewardTokenAddress).safeTransfer(\n vaultAddress,\n aaveBalance\n );\n }\n }\n\n // Collect avaiable rewards and restart the cooldown timer, if either of\n // those should be run.\n if (block.timestamp > windowStart || cooldown == 0) {\n // aToken addresses for incentives controller\n address[] memory aTokens = new address[](assetsMapped.length);\n for (uint256 i = 0; i < assetsMapped.length; i++) {\n aTokens[i] = _getATokenFor(assetsMapped[i]);\n }\n\n // 1. If we have rewards availabile, collect them\n uint256 pendingRewards = incentivesController.getRewardsBalance(\n aTokens,\n address(this)\n );\n if (pendingRewards > 0) {\n // Because getting more stkAAVE from the incentives controller\n // with claimRewards() may push the stkAAVE cooldown time\n // forward, it is called after stakedAAVE has been turned into\n // AAVE.\n uint256 collected = incentivesController.claimRewards(\n aTokens,\n pendingRewards,\n address(this)\n );\n require(collected == pendingRewards, \"AAVE reward difference\");\n }\n\n // 2. Start cooldown counting down.\n if (stkAave.balanceOf(address(this)) > 0) {\n // Protected with if since cooldown call would revert\n // if no stkAave balance.\n stkAave.cooldown();\n }\n }\n }\n}\n" + }, + "contracts/strategies/IAave.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface for Aaves Lending Pool\n * Documentation: https://developers.aave.com/#lendingpool\n */\ninterface IAaveLendingPool {\n /**\n * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n * - E.g. User deposits 100 USDC and gets in return 100 aUSDC\n * @param asset The address of the underlying asset to deposit\n * @param amount The amount to be deposited\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n **/\n function deposit(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n\n /**\n * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n * @param asset The address of the underlying asset to withdraw\n * @param amount The underlying amount to be withdrawn\n * - Send the value type(uint256).max in order to withdraw the whole aToken balance\n * @param to Address that will receive the underlying, same as msg.sender if the user\n * wants to receive it on his own wallet, or a different address if the beneficiary is a\n * different wallet\n * @return The final amount withdrawn\n **/\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external returns (uint256);\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" + }, + "contracts/strategies/IAaveStakeToken.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IAaveStakedToken {\n function COOLDOWN_SECONDS() external returns (uint256);\n\n function UNSTAKE_WINDOW() external returns (uint256);\n\n function balanceOf(address addr) external returns (uint256);\n\n function redeem(address to, uint256 amount) external;\n\n function stakersCooldowns(address addr) external returns (uint256);\n\n function cooldown() external;\n}\n" + }, + "contracts/strategies/IAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface IAaveIncentivesController {\n event RewardsAccrued(address indexed user, uint256 amount);\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n uint256 amount\n );\n\n event RewardsClaimed(\n address indexed user,\n address indexed to,\n address indexed claimer,\n uint256 amount\n );\n\n event ClaimerSet(address indexed user, address indexed claimer);\n\n /*\n * @dev Returns the configuration of the distribution for a certain asset\n * @param asset The address of the reference asset of the distribution\n * @return The asset index, the emission per second and the last updated timestamp\n **/\n function getAssetData(address asset)\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /**\n * @dev Whitelists an address to claim the rewards on behalf of another address\n * @param user The address of the user\n * @param claimer The address of the claimer\n */\n function setClaimer(address user, address claimer) external;\n\n /**\n * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)\n * @param user The address of the user\n * @return The claimer address\n */\n function getClaimer(address user) external view returns (address);\n\n /**\n * @dev Configure assets for a certain rewards emission\n * @param assets The assets to incentivize\n * @param emissionsPerSecond The emission for each asset\n */\n function configureAssets(\n address[] calldata assets,\n uint256[] calldata emissionsPerSecond\n ) external;\n\n /**\n * @dev Called by the corresponding asset on any update that affects the rewards distribution\n * @param asset The address of the user\n * @param userBalance The balance of the user of the asset in the lending pool\n * @param totalSupply The total supply of the asset in the lending pool\n **/\n function handleAction(\n address asset,\n uint256 userBalance,\n uint256 totalSupply\n ) external;\n\n /**\n * @dev Returns the total of rewards of an user, already accrued + not yet accrued\n * @param user The address of the user\n * @return The rewards\n **/\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool,\n * accumulating the pending rewards\n * @param amount Amount of rewards to claim\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewards(\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256);\n\n /**\n * @dev Claims reward for an user on behalf, on all the assets of the\n * lending pool, accumulating the pending rewards. The caller must\n * be whitelisted via \"allowClaimOnBehalf\" function by the RewardsAdmin role manager\n * @param amount Amount of rewards to claim\n * @param user Address to check and claim rewards\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewardsOnBehalf(\n address[] calldata assets,\n uint256 amount,\n address user,\n address to\n ) external returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @return the unclaimed user rewards\n */\n function getUserUnclaimedRewards(address user)\n external\n view\n returns (uint256);\n\n /**\n * @dev returns the unclaimed rewards of the user\n * @param user the address of the user\n * @param asset The asset to incentivize\n * @return the user index for the asset\n */\n function getUserAssetData(address user, address asset)\n external\n view\n returns (uint256);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function REWARD_TOKEN() external view returns (address);\n\n /**\n * @dev for backward compatibility with previous implementation of the Incentives controller\n */\n function PRECISION() external view returns (uint8);\n\n /**\n * @dev Gets the distribution end timestamp of the emissions\n */\n function DISTRIBUTION_END() external view returns (uint256);\n}\n" + }, + "contracts/mocks/MockAave.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport { MintableERC20 } from \"./MintableERC20.sol\";\nimport { IAaveLendingPool, ILendingPoolAddressesProvider } from \"../strategies/IAave.sol\";\nimport { StableMath } from \"../utils/StableMath.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 MintableERC20 {\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 ) ERC20(_name, _symbol) {\n lendingPool = _lendingPool;\n underlyingToken = _underlyingToken;\n // addMinter(_lendingPool);\n }\n\n function decimals() public view override returns (uint8) {\n return ERC20(address(underlyingToken)).decimals();\n }\n\n function poolRedeem(uint256 _amount, address _to) external {\n require(msg.sender == lendingPool, \"pool only\");\n // Redeem these a Tokens\n _burn(_to, _amount);\n // For the underlying\n underlyingToken.safeTransferFrom(lendingPool, _to, _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 = payable(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, type(uint256).max);\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 address _to,\n uint16 /*_referralCode*/\n ) external override {\n uint256 previousBal = IERC20(reserveToAToken[_reserve]).balanceOf(\n msg.sender\n );\n uint256 interest = previousBal.mulTruncate(factor);\n MintableERC20(reserveToAToken[_reserve]).mintTo(msg.sender, interest);\n // Take their reserve\n IERC20(_reserve).safeTransferFrom(msg.sender, address(this), _amount);\n // Credit them with aToken\n MintableERC20(reserveToAToken[_reserve]).mintTo(_to, _amount);\n }\n\n function withdraw(\n address asset,\n uint256 amount,\n address to\n ) external override returns (uint256) {\n MockAToken atoken = MockAToken(reserveToAToken[asset]);\n atoken.poolRedeem(amount, to);\n return amount;\n }\n\n function getLendingPool() external view override returns (address) {\n return pool;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurveGauge.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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) {\n lpToken = _lpToken;\n }\n\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n function deposit(uint256 _value, address _account) external override {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _value);\n _balances[_account] += _value;\n }\n\n function withdraw(uint256 _value) external override {\n IERC20(lpToken).transfer(msg.sender, _value);\n _balances[msg.sender] -= _value;\n }\n}\n" + }, + "contracts/staking/SingleAssetStaking.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.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 address public transferAgent;\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] < type(uint240).max, \"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.push(); // 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 < type(uint240).max, \"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 /**\n * @dev Use to transfer all the stakes of an account in the case that the account is compromised\n * Requires access to both the account itself and the transfer agent\n * @param _frmAccount the address to transfer from\n * @param _dstAccount the address to transfer to(must be a clean address with no stakes)\n * @param r r portion of the signature by the transfer agent\n * @param s s portion of the signature\n * @param v v portion of the signature\n */\n function transferStakes(\n address _frmAccount,\n address _dstAccount,\n bytes32 r,\n bytes32 s,\n uint8 v\n ) external {\n require(transferAgent == msg.sender, \"must be transfer agent\");\n Stake[] storage dstStakes = userStakes[_dstAccount];\n require(dstStakes.length == 0, \"Dest stakes must be empty\");\n require(_frmAccount != address(0), \"from account not set\");\n Stake[] storage stakes = userStakes[_frmAccount];\n require(stakes.length > 0, \"Nothing to transfer\");\n\n // matches ethers.signMsg(ethers.utils.solidityPack([string(4), address, adddress, address]))\n bytes32 hash = keccak256(\n abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n64\",\n abi.encodePacked(\n \"tran\",\n address(this),\n _frmAccount,\n _dstAccount\n )\n )\n );\n require(ecrecover(hash, v, r, s) == _frmAccount, \"Transfer not authed\");\n\n // copy the stakes into the dstAccount array and delete the old one\n userStakes[_dstAccount] = stakes;\n delete userStakes[_frmAccount];\n emit StakesTransfered(_frmAccount, _dstAccount, stakes.length);\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 the agent that will authorize transfers\n * @param _agent Address of agent\n */\n function setTransferAgent(address _agent) external onlyGovernor {\n transferAgent = _agent;\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 event StakesTransfered(\n address indexed fromUser,\n address toUser,\n uint256 numStakes\n );\n}\n" + }, + "contracts/proxies/InitializeGovernedUpgradeabilityProxy.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Governable } from \"../governance/Governable.sol\";\n\n/**\n * @title BaseGovernedUpgradeabilityProxy\n * @dev This contract combines an upgradeability proxy with our governor system.\n * It is based on an older version of OpenZeppelins BaseUpgradeabilityProxy\n * with Solidity ^0.8.0.\n * @author Origin Protocol Inc\n */\ncontract InitializeGovernedUpgradeabilityProxy is Governable {\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 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\n * the proxied contract.\n * It should include the signature and the parameters of the function to be\n * 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\n * 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 /**\n * @dev Fallback function.\n * Implemented entirely in `_fallback`.\n */\n fallback() external payable {\n _fallback();\n }\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 _impl Address to delegate.\n */\n function _delegate(address _impl) 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(), _impl, 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 /**\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 * @dev fallback implementation.\n * Extracted to enable manual triggering.\n */\n function _fallback() internal {\n _willFallback();\n _delegate(_implementation());\n }\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 =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation.\n * @return impl 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(\n Address.isContract(newImplementation),\n \"Cannot set a proxy implementation to a non-contract address\"\n );\n\n bytes32 slot = IMPLEMENTATION_SLOT;\n\n assembly {\n sstore(slot, newImplementation)\n }\n }\n}\n" + }, + "contracts/proxies/Proxies.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { InitializeGovernedUpgradeabilityProxy } 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 AaveStrategyProxy delegates calls to a AaveStrategy implementation\n */\ncontract AaveStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ThreePoolStrategyProxy delegates calls to a ThreePoolStrategy implementation\n */\ncontract ThreePoolStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n\n/**\n * @notice ConvexStrategyProxy delegates calls to a ConvexStrategy implementation\n */\ncontract ConvexStrategyProxy is InitializeGovernedUpgradeabilityProxy {\n\n}\n" + }, + "contracts/mocks/MockNonRebasing.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/flipper/Flipper.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../governance/Governable.sol\";\nimport \"../token/OUSD.sol\";\nimport \"../interfaces/Tether.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// Contract to exchange usdt, usdc, dai from and to ousd.\n// - 1 to 1. No slippage\n// - Optimized for low gas usage\n// - No guarantee of availability\n\ncontract Flipper is Governable {\n using SafeERC20 for IERC20;\n\n uint256 constant MAXIMUM_PER_TRADE = (25000 * 1e18);\n\n // Settable coin addresses allow easy testing and use of mock currencies.\n IERC20 immutable dai;\n OUSD immutable ousd;\n IERC20 immutable usdc;\n Tether immutable usdt;\n\n // ---------------------\n // Dev constructor\n // ---------------------\n constructor(\n address _dai,\n address _ousd,\n address _usdc,\n address _usdt\n ) {\n require(address(_dai) != address(0));\n require(address(_ousd) != address(0));\n require(address(_usdc) != address(0));\n require(address(_usdt) != address(0));\n dai = IERC20(_dai);\n ousd = OUSD(_ousd);\n usdc = IERC20(_usdc);\n usdt = Tether(_usdt);\n }\n\n // -----------------\n // Trading functions\n // -----------------\n\n /// @notice Purchase OUSD with Dai\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n dai.transferFrom(msg.sender, address(this), amount),\n \"DAI transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for Dai\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForDai(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(dai.transfer(msg.sender, amount), \"DAI transfer failed\");\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDC\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n require(\n usdc.transferFrom(msg.sender, address(this), amount / 1e12),\n \"USDC transfer failed\"\n );\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDC\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdc(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n require(\n usdc.transfer(msg.sender, amount / 1e12),\n \"USDC transfer failed\"\n );\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n /// @notice Purchase OUSD with USDT\n /// @param amount Amount of OUSD to purchase, in 18 fixed decimals.\n function buyOusdWithUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // Potential rounding error is an intentional trade off\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transferFrom(msg.sender, address(this), amount / 1e12);\n require(ousd.transfer(msg.sender, amount), \"OUSD transfer failed\");\n }\n\n /// @notice Sell OUSD for USDT\n /// @param amount Amount of OUSD to sell, in 18 fixed decimals.\n function sellOusdForUsdt(uint256 amount) external {\n require(amount <= MAXIMUM_PER_TRADE, \"Amount too large\");\n // USDT does not return a boolean and reverts,\n // so no need for a require.\n usdt.transfer(msg.sender, amount / 1e12);\n require(\n ousd.transferFrom(msg.sender, address(this), amount),\n \"OUSD transfer failed\"\n );\n }\n\n // --------------------\n // Governance functions\n // --------------------\n\n /// @dev Opting into yield reduces the gas cost per transfer by about 4K, since\n /// ousd needs to do less accounting and one less storage write.\n function rebaseOptIn() external onlyGovernor nonReentrant {\n ousd.rebaseOptIn();\n }\n\n /// @notice Owner function to withdraw a specific amount of a token\n function withdraw(address token, uint256 amount)\n external\n onlyGovernor\n nonReentrant\n {\n IERC20(token).safeTransfer(_governor(), amount);\n }\n\n /// @notice Owner function to withdraw all tradable tokens\n /// @dev Contract will not perform any swaps until liquidity is provided\n /// again by transferring assets to the contract.\n function withdrawAll() external onlyGovernor nonReentrant {\n IERC20(dai).safeTransfer(_governor(), dai.balanceOf(address(this)));\n IERC20(ousd).safeTransfer(_governor(), ousd.balanceOf(address(this)));\n IERC20(address(usdt)).safeTransfer(\n _governor(),\n usdt.balanceOf(address(this))\n );\n IERC20(usdc).safeTransfer(_governor(), usdc.balanceOf(address(this)));\n }\n}\n" + }, + "contracts/interfaces/Tether.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ninterface Tether {\n function transfer(address to, uint256 value) external;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external;\n\n function balanceOf(address) external returns (uint256);\n}\n" + }, + "contracts/liquidity/LiquidityReward.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.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 // total Supply that is accounted for via deposit/withdraw so that our rewards calc are stable\n uint256 public totalSupply;\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 event DrainExtraReward(address indexed user, uint256 amount);\n event DrainExtraLP(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(totalSupply),\n totalRewardDebt\n );\n\n require(_numBlocks > 0, \"startCampaign: zero blocks\");\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 drainExtraRewards() external onlyGovernor {\n require(endBlock < block.number, \"drainExtraRewards:Campaign active\");\n updatePool();\n uint256 extraRewards = reward.balanceOf(address(this)).sub(\n subDebt(\n pool.accRewardPerShare.mulTruncate(totalSupply),\n totalRewardDebt\n )\n );\n if (extraRewards > 0) {\n emit DrainExtraReward(msg.sender, extraRewards);\n reward.safeTransfer(msg.sender, extraRewards);\n }\n }\n\n function drainExtraLP() external onlyGovernor {\n uint256 extraLP = pool.lpToken.balanceOf(address(this)).sub(\n totalSupply\n );\n require(extraLP > 0, \"drainExtraLP:no extra\");\n emit DrainExtraLP(msg.sender, extraLP);\n pool.lpToken.safeTransfer(msg.sender, extraLP);\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 if (totalSupply != 0) {\n uint256 multiplier = getCampaignMultiplier(block.number);\n uint256 incReward = multiplier.mul(rewardPerBlock);\n accRewardPerShare = accRewardPerShare.add(\n incReward.divPrecisely(totalSupply)\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 if (block.number > pool.lastRewardBlock && totalSupply != 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(totalSupply)\n );\n return\n subDebt(\n accRewardPerShare.mulTruncate(totalSupply),\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 if (totalSupply == 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(totalSupply)\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 totalSupply = totalSupply.add(_amount);\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 uint256 pending = 0;\n if (_claim) {\n //This is an optimization so we don't modify the storage variable twice\n pending = subDebt(\n user.amount.mulTruncate(pool.accRewardPerShare),\n user.rewardDebt\n );\n\n newDebt += int256(pending);\n }\n\n user.rewardDebt += newDebt;\n totalRewardDebt += newDebt;\n emit Withdraw(msg.sender, _amount);\n // actually make the changes to the amount and debt\n if (_amount > 0) {\n user.amount = user.amount.sub(_amount);\n totalSupply = totalSupply.sub(_amount, \"withdraw: total overflow\");\n }\n //putting this all at the end to avoid reentrancy error\n if (pending > 0) {\n emit Claim(msg.sender, pending);\n reward.safeTransfer(msg.sender, pending);\n }\n if (_amount > 0) {\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n }\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/governance/InitializableGovernable.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD InitializableGovernable Contract\n * @author Origin Protocol Inc\n */\nimport { Initializable } from \"../utils/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/compensation/CompensationClaims.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SafeMath } from \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\nimport { Initializable } from \"../utils/Initializable.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) 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" + }, + "contracts/crytic/PropertiesOUSDTransferable.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./interfaces.sol\";\nimport \"../token/OUSD.sol\";\n\ncontract PropertiesOUSDTransferable is CryticInterface, OUSD {\n function init_total_supply() public view returns (bool) {\n return\n this.totalSupply() >= 0 && this.totalSupply() == initialTotalSupply;\n }\n\n function init_owner_balance() public view returns (bool) {\n return initialBalance_owner == this.balanceOf(crytic_owner);\n }\n\n function init_user_balance() public view returns (bool) {\n return initialBalance_user == this.balanceOf(crytic_user);\n }\n\n function init_attacker_balance() public view returns (bool) {\n return initialBalance_attacker == this.balanceOf(crytic_attacker);\n }\n\n function init_caller_balance() public view returns (bool) {\n return this.balanceOf(msg.sender) > 0;\n }\n\n function init_total_supply_is_balances() public view 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()\n public\n view\n returns (bool)\n {\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()\n public\n view\n returns (bool)\n {\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\ncontract CryticInterface {\n address internal crytic_owner =\n address(0x627306090abaB3A6e1400e9345bC60c78a8BEf57);\n address internal crytic_user =\n address(0xf17f52151EbEF6C7334FAD080c5704D77216b732);\n address internal crytic_attacker =\n address(0xC5fdf4076b8F3A5357c5E395ab970B5B54098Fef);\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./PropertiesOUSDTransferable.sol\";\n\ncontract TestOUSDTransferable is PropertiesOUSDTransferable {\n constructor() {\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; // Already set by parent\n // rebasingCreditsPerToken = 1e27; // Already set by parent\n vaultAddress = crytic_owner;\n // nonRebasingSupply = 0; // Already set by parent\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" + }, + "contracts/oracle/MixOracle.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\n// DEPRECATED - This contract is no longer used in production\npragma solidity ^0.8.0;\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) {\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 * @param 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 override\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 * @param 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 override\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/interfaces/IMinMaxOracle.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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/mocks/MockOracle.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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)\n external\n view\n override\n returns (uint256)\n {\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)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(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)\n external\n view\n override\n returns (uint256)\n {\n uint256[] storage pMinMax = pricesMinMax[\n keccak256(abi.encodePacked(symbol))\n ];\n return (pMinMax[1] * ethMax) / 1e6;\n }\n}\n" + }, + "contracts/mocks/MockUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 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 override returns (uint256[] memory amounts) {\n // Give 1:1\n uint256 amountOut = amountIn.scaleBy(\n Helpers.getDecimals(tok1),\n Helpers.getDecimals(tok0)\n );\n require(amountOut >= amountOutMin, \"Slippage error\");\n IERC20(tok0).transferFrom(msg.sender, address(this), amountIn);\n IERC20(tok1).transfer(to, amountOut);\n }\n\n struct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n }\n\n function exactInput(ExactInputParams calldata params)\n external\n payable\n returns (uint256 amountOut)\n {\n amountOut = params.amountIn.scaleBy(\n Helpers.getDecimals(tok1),\n Helpers.getDecimals(tok0)\n );\n IERC20(tok0).transferFrom(msg.sender, address(this), params.amountIn);\n IERC20(tok1).transfer(params.recipient, amountOut);\n require(\n amountOut >= params.amountOutMinimum,\n \"UniswapMock: amountOut less than amountOutMinimum\"\n );\n return amountOut;\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 override\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 function WETH() external pure override returns (address) {\n return address(0);\n }\n}\n" + }, + "contracts/mocks/MockRebornMinter.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"hardhat/console.sol\";\n\ncontract Sanctum {\n address public asset;\n address public vault;\n address public reborner;\n bool public shouldAttack = false;\n uint256 public targetMethod;\n address public ousdContract;\n\n constructor(address _asset, address _vault) {\n asset = _asset;\n vault = _vault;\n }\n\n function deploy(uint256 salt, bytes memory bytecode)\n public\n returns (address addr)\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)\n }\n require(addr != address(0), \"Create2: Failed on deploy\");\n }\n\n function computeAddress(uint256 salt, bytes memory bytecode)\n public\n view\n returns (address)\n {\n bytes32 bytecodeHashHash = keccak256(bytecode);\n bytes32 _data = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n bytecodeHashHash\n )\n );\n return address(bytes20(_data << 96));\n }\n\n function setShouldAttack(bool _shouldAttack) public {\n shouldAttack = _shouldAttack;\n }\n\n function setTargetMethod(uint256 target) public {\n targetMethod = target;\n }\n\n function setOUSDAddress(address _ousdContract) public {\n ousdContract = _ousdContract;\n }\n}\n\ncontract Reborner {\n Sanctum sanctum;\n bool logging = false;\n\n constructor(address _sanctum) {\n log(\"We are created...\");\n sanctum = Sanctum(_sanctum);\n if (sanctum.shouldAttack()) {\n log(\"We are attacking now...\");\n\n uint256 target = sanctum.targetMethod();\n\n if (target == 1) {\n redeem();\n } else if (target == 2) {\n transfer();\n } else {\n mint();\n }\n }\n }\n\n function mint() public {\n log(\"We are attempting to mint..\");\n address asset = sanctum.asset();\n address vault = sanctum.vault();\n IERC20(asset).approve(vault, 1e18);\n IVault(vault).mint(asset, 1e18, 0);\n log(\"We are now minting..\");\n }\n\n function redeem() public {\n log(\"We are attempting to redeem..\");\n address vault = sanctum.vault();\n IVault(vault).redeem(1e18, 1e18);\n log(\"We are now redeeming..\");\n }\n\n function transfer() public {\n log(\"We are attempting to transfer..\");\n address ousd = sanctum.ousdContract();\n require(IERC20(ousd).transfer(address(1), 1e18), \"transfer failed\");\n log(\"We are now transfering..\");\n }\n\n function bye() public {\n log(\"We are now destructing..\");\n selfdestruct(payable(msg.sender));\n }\n\n function log(string memory message) internal view {\n if (logging) {\n console.log(message);\n }\n }\n}\n" + }, + "hardhat/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >= 0.4.22 <0.9.0;\n\nlibrary console {\n\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\n\n\tfunction _sendLogPayload(bytes memory payload) private view {\n\t\tuint256 payloadLength = payload.length;\n\t\taddress consoleAddress = CONSOLE_ADDRESS;\n\t\tassembly {\n\t\t\tlet payloadStart := add(payload, 32)\n\t\t\tlet r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)\n\t\t}\n\t}\n\n\tfunction log() internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log()\"));\n\t}\n\n\tfunction logInt(int p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(int)\", p0));\n\t}\n\n\tfunction logUint(uint p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint)\", p0));\n\t}\n\n\tfunction logString(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction logBool(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction logAddress(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction logBytes(bytes memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n\t}\n\n\tfunction logBytes1(bytes1 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n\t}\n\n\tfunction logBytes2(bytes2 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n\t}\n\n\tfunction logBytes3(bytes3 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n\t}\n\n\tfunction logBytes4(bytes4 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n\t}\n\n\tfunction logBytes5(bytes5 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n\t}\n\n\tfunction logBytes6(bytes6 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n\t}\n\n\tfunction logBytes7(bytes7 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n\t}\n\n\tfunction logBytes8(bytes8 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n\t}\n\n\tfunction logBytes9(bytes9 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n\t}\n\n\tfunction logBytes10(bytes10 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n\t}\n\n\tfunction logBytes11(bytes11 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n\t}\n\n\tfunction logBytes12(bytes12 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n\t}\n\n\tfunction logBytes13(bytes13 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n\t}\n\n\tfunction logBytes14(bytes14 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n\t}\n\n\tfunction logBytes15(bytes15 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n\t}\n\n\tfunction logBytes16(bytes16 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n\t}\n\n\tfunction logBytes17(bytes17 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n\t}\n\n\tfunction logBytes18(bytes18 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n\t}\n\n\tfunction logBytes19(bytes19 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n\t}\n\n\tfunction logBytes20(bytes20 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n\t}\n\n\tfunction logBytes21(bytes21 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n\t}\n\n\tfunction logBytes22(bytes22 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n\t}\n\n\tfunction logBytes23(bytes23 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n\t}\n\n\tfunction logBytes24(bytes24 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n\t}\n\n\tfunction logBytes25(bytes25 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n\t}\n\n\tfunction logBytes26(bytes26 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n\t}\n\n\tfunction logBytes27(bytes27 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n\t}\n\n\tfunction logBytes28(bytes28 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n\t}\n\n\tfunction logBytes29(bytes29 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n\t}\n\n\tfunction logBytes30(bytes30 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n\t}\n\n\tfunction logBytes31(bytes31 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n\t}\n\n\tfunction logBytes32(bytes32 p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n\t}\n\n\tfunction log(uint p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint)\", p0));\n\t}\n\n\tfunction log(string memory p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n\t}\n\n\tfunction log(bool p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n\t}\n\n\tfunction log(address p0) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n\t}\n\n\tfunction log(uint p0, uint p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint)\", p0, p1));\n\t}\n\n\tfunction log(uint p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string)\", p0, p1));\n\t}\n\n\tfunction log(uint p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool)\", p0, p1));\n\t}\n\n\tfunction log(uint p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, uint p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n\t}\n\n\tfunction log(string memory p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, uint p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n\t}\n\n\tfunction log(bool p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n\t}\n\n\tfunction log(address p0, uint p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint)\", p0, p1));\n\t}\n\n\tfunction log(address p0, string memory p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n\t}\n\n\tfunction log(address p0, bool p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n\t}\n\n\tfunction log(address p0, address p1) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n\t}\n\n\tfunction log(uint p0, uint p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, uint p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, uint p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, uint p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, string memory p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, bool p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, address p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, uint p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, uint p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(bool p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, uint p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, bool p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, uint p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, bool p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n\t}\n\n\tfunction log(address p0, address p1, address p2) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n\t}\n\n\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,uint,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(uint p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(uint,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,uint,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,uint,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(bool p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, uint p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,uint,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, bool p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, uint p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, bool p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, uint p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, bool p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n\t}\n\n\tfunction log(address p0, address p1, address p2, address p3) internal view {\n\t\t_sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n\t}\n\n}\n" + }, + "contracts/mocks/MockStkAave.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./MintableERC20.sol\";\n\ncontract MockStkAave is MintableERC20 {\n uint256 public COOLDOWN_SECONDS = 864000;\n uint256 public UNSTAKE_WINDOW = 172800;\n address public STAKED_TOKEN;\n\n mapping(address => uint256) public stakerRewardsToClaim;\n mapping(address => uint256) public stakersCooldowns;\n\n using SafeERC20 for IERC20;\n\n constructor(address _stakedToken) ERC20(\"Staked Aave\", \"stkAAVE\") {\n STAKED_TOKEN = _stakedToken;\n }\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function setStakedToken(address _stakedToken) external {\n STAKED_TOKEN = _stakedToken;\n }\n\n /**\n * @dev Redeems staked tokens, and stop earning rewards\n * @param to Address to redeem to\n * @param amount Amount to redeem\n **/\n function redeem(address to, uint256 amount) external {\n uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender];\n uint256 windowStart = cooldownStartTimestamp + COOLDOWN_SECONDS;\n require(amount != 0, \"INVALID_ZERO_AMOUNT\");\n require(block.timestamp > windowStart, \"INSUFFICIENT_COOLDOWN\");\n require(\n block.timestamp - windowStart <= UNSTAKE_WINDOW,\n \"UNSTAKE_WINDOW_FINISHED\"\n );\n uint256 balanceOfMessageSender = balanceOf(msg.sender);\n uint256 amountToRedeem = (amount > balanceOfMessageSender)\n ? balanceOfMessageSender\n : amount;\n\n stakersCooldowns[msg.sender] = 0;\n _burn(msg.sender, amountToRedeem);\n IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem);\n }\n\n /**\n * @dev Activates the cooldown period to unstake\n * - It can't be called if the user is not staking\n **/\n function cooldown() external {\n require(balanceOf(msg.sender) != 0, \"INVALID_BALANCE_ON_COOLDOWN\");\n stakersCooldowns[msg.sender] = block.timestamp;\n }\n\n /**\n * @dev Test helper function to allow changing the cooldown\n **/\n function setCooldown(address account, uint256 _cooldown) external {\n stakersCooldowns[account] = _cooldown;\n }\n}\n" + }, + "contracts/mocks/MockAaveIncentivesController.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport { MockStkAave } from \"./MockStkAave.sol\";\n\ncontract MockAaveIncentivesController {\n mapping(address => uint256) private rewards;\n MockStkAave public REWARD_TOKEN;\n\n constructor(address _reward_token) {\n REWARD_TOKEN = MockStkAave(_reward_token);\n }\n\n function setRewardsBalance(address user, uint256 amount) external {\n rewards[user] = amount;\n }\n\n /**\n * @dev Returns the total of rewards of an user, already accrued + not yet accrued\n * @param user The address of the user\n * @return The rewards\n **/\n function getRewardsBalance(address[] calldata assets, address user)\n external\n view\n returns (uint256)\n {\n return rewards[user];\n }\n\n /**\n * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards\n * @param amount Amount of rewards to claim\n * @param to Address that will be receiving the rewards\n * @return Rewards claimed\n **/\n function claimRewards(\n address[] calldata assets,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(amount > 0);\n require(rewards[to] == amount);\n REWARD_TOKEN.mint(amount);\n require(REWARD_TOKEN.transfer(to, amount));\n rewards[to] = 0;\n return amount;\n }\n}\n" + }, + "contracts/mocks/curve/MockCurvePool.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\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 {\n using StableMath for uint256;\n\n address[] public coins;\n uint256[3] public balances;\n address lpToken;\n\n constructor(address[3] memory _coins, address _lpToken) {\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(18, assetDecimals);\n balances[i] = balances[i] + _amounts[i];\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[uint128(_index)]);\n return _amount.scaleBy(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[uint128(_index)] = _amount;\n uint256 amount = calc_withdraw_one_coin(_amount, _index);\n IERC20(coins[uint128(_index)]).transfer(msg.sender, amount);\n balances[uint128(_index)] = balances[uint128(_index)] - amount;\n }\n\n function get_virtual_price() external pure returns (uint256) {\n return 1 * 10**18;\n }\n\n function remove_liquidity(uint256 _amount, uint256[3] memory _min_amounts)\n public\n {\n IERC20(lpToken).transferFrom(msg.sender, address(this), _amount);\n uint256 totalSupply = IERC20(lpToken).totalSupply();\n for (uint256 i = 0; i < 3; i++) {\n uint256 amount = (_amount / totalSupply) *\n IERC20(coins[i]).balanceOf(address(this));\n IERC20(coins[i]).transfer(msg.sender, amount);\n balances[i] = balances[i] - amount;\n }\n }\n\n function remove_liquidity_imbalance(\n uint256[3] memory _amounts,\n uint256 _max_burned_tokens\n ) public {\n IERC20(lpToken).transferFrom(\n msg.sender,\n address(this),\n _max_burned_tokens\n );\n for (uint256 i = 0; i < _amounts.length; i++) {\n IERC20(coins[i]).transfer(msg.sender, _amounts[i]);\n balances[i] = balances[i] - _amounts[i];\n }\n }\n}\n" + }, + "contracts/mocks/curve/MockCRVMinter.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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) {\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/mocks/MockDAI.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockDAI is MintableERC20 {\n constructor() ERC20(\"DAI\", \"DAI\") {}\n}\n" + }, + "contracts/mocks/MockCOMP.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockCOMP is MintableERC20 {\n constructor() ERC20(\"COMP\", \"COMP\") {}\n}\n" + }, + "contracts/mocks/MockAAVEToken.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"./MintableERC20.sol\";\n\ncontract MockAAVEToken is MintableERC20 {\n constructor() ERC20(\"AAVE\", \"AAVE\") {}\n}\n" + }, + "contracts/mocks/curve/MockCVX.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCVX is MintableERC20 {\n constructor() ERC20(\"CVX\", \"CVX DAO Token\") {}\n}\n" + }, + "contracts/mocks/curve/MockCRV.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract MockCRV is MintableERC20 {\n constructor() ERC20(\"Curve DAO Token\", \"CRV\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n}\n" + }, + "contracts/mocks/curve/Mock3CRV.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\nimport \"../MintableERC20.sol\";\n\ncontract Mock3CRV is MintableERC20 {\n constructor() ERC20(\"Curve.fi DAI/USDC/USDT\", \"3Crv\") {}\n\n function decimals() public pure override returns (uint8) {\n return 18;\n }\n\n function burnFrom(address from, uint256 value) public {\n _burn(from, value);\n }\n}\n" + }, + "contracts/timelock/Timelock.sol": { + "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Timelock Contract\n * @author Origin Protocol Inc\n */\nimport \"@openzeppelin/contracts/utils/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_) {\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 _getRevertMsg(bytes memory _returnData)\n internal\n pure\n returns (string memory)\n {\n // If the _res length is less than 68, then the transaction failed\n // silently (without a revert message)\n if (_returnData.length < 68) return \"Transaction reverted silently\";\n\n assembly {\n // Slice the sighash.\n _returnData := add(_returnData, 0x04)\n }\n return abi.decode(_returnData, (string));\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\n if (!success) {\n revert(_getRevertMsg(returnData));\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": "// SPDX-License-Identifier: agpl-3.0\npragma solidity ^0.8.0;\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 = 32;\n\n // @notice Possible states that a proposal may be in\n enum ProposalState {\n Pending,\n Queued,\n Expired,\n Executed\n }\n\n constructor(address admin_, uint256 delay_) Timelock(admin_, delay_) {}\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 + 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 + 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[\n keccak256(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" + } + }, + "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/smoke/mintRedeemTest.js b/contracts/smoke/mintRedeemTest.js index 585841e45c..6ab639136f 100644 --- a/contracts/smoke/mintRedeemTest.js +++ b/contracts/smoke/mintRedeemTest.js @@ -199,7 +199,6 @@ async function afterDeploy(hre, beforeDeployData) { const ousdAfterMint = await testMint(hre, beforeDeployData); await testRedeem(ousdAfterMint); await testTransfer(); - await testMultipleMint(); } module.exports = { diff --git a/contracts/storageLayout/mainnet/ConvexStrategy.json b/contracts/storageLayout/mainnet/ConvexStrategy.json index 07ac81aa02..7a37dc8574 100644 --- a/contracts/storageLayout/mainnet/ConvexStrategy.json +++ b/contracts/storageLayout/mainnet/ConvexStrategy.json @@ -70,25 +70,25 @@ "contract": "ConvexStrategy", "label": "cvxDepositorAddress", "type": "t_address", - "src": "contracts/strategies/ConvexStrategy.sol:27" + "src": "contracts/strategies/ConvexStrategy.sol:32" }, { "contract": "ConvexStrategy", "label": "cvxRewardStakerAddress", "type": "t_address", - "src": "contracts/strategies/ConvexStrategy.sol:28" + "src": "contracts/strategies/ConvexStrategy.sol:33" }, { "contract": "ConvexStrategy", - "label": "crvRewardTokenAddress", + "label": "cvxRewardTokenAddress", "type": "t_address", - "src": "contracts/strategies/ConvexStrategy.sol:29" + "src": "contracts/strategies/ConvexStrategy.sol:34" }, { "contract": "ConvexStrategy", "label": "cvxDepositorPTokenId", "type": "t_uint256", - "src": "contracts/strategies/ConvexStrategy.sol:30" + "src": "contracts/strategies/ConvexStrategy.sol:35" } ], "types": { diff --git a/contracts/tasks/debug.js b/contracts/tasks/debug.js index b6dc81984a..de1268048d 100644 --- a/contracts/tasks/debug.js +++ b/contracts/tasks/debug.js @@ -345,6 +345,10 @@ async function debug(taskArguments, hre) { "rewardTokenAddress:\t\t", await threePoolStrategy.rewardTokenAddress() ); + console.log( + "cvxRewardTokenAddress:\t\t", + await threePoolStrategy.cvxRewardTokenAddress() + ); console.log( "rewardLiquidationThreshold:\t", (await threePoolStrategy.rewardLiquidationThreshold()).toString() diff --git a/dapp/network.mainnet.json b/dapp/network.mainnet.json index 2c0ea25943..49e4fc31bf 100644 --- a/dapp/network.mainnet.json +++ b/dapp/network.mainnet.json @@ -2374,8 +2374,27 @@ ] }, "ConvexStrategy": { - "address": "0x08f3a0637851aA1B0E0750aA3d46E0E356f349aC", + "address": "0x16156a06bD1bd2d80134EA1Ee7e5FaEBDbFa20aa", "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_oldAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_newAddress", + "type": "address" + } + ], + "name": "CvxRewardTokenAddressUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -2636,6 +2655,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "cvxRewardTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -2693,7 +2725,7 @@ }, { "internalType": "address", - "name": "_crvRewardTokenAddress", + "name": "_cvxRewardTokenAddress", "type": "address" }, { @@ -2832,6 +2864,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_cvxRewardTokenAddress", + "type": "address" + } + ], + "name": "setCvxRewardTokenAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/dapp/prod.network.json b/dapp/prod.network.json index 2c0ea25943..49e4fc31bf 100644 --- a/dapp/prod.network.json +++ b/dapp/prod.network.json @@ -2374,8 +2374,27 @@ ] }, "ConvexStrategy": { - "address": "0x08f3a0637851aA1B0E0750aA3d46E0E356f349aC", + "address": "0x16156a06bD1bd2d80134EA1Ee7e5FaEBDbFa20aa", "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_oldAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_newAddress", + "type": "address" + } + ], + "name": "CvxRewardTokenAddressUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -2636,6 +2655,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "cvxRewardTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -2693,7 +2725,7 @@ }, { "internalType": "address", - "name": "_crvRewardTokenAddress", + "name": "_cvxRewardTokenAddress", "type": "address" }, { @@ -2832,6 +2864,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_cvxRewardTokenAddress", + "type": "address" + } + ], + "name": "setCvxRewardTokenAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ {