diff --git a/contracts/XINV.sol b/contracts/XINV.sol index 7c41b7be7..428119bde 100644 --- a/contracts/XINV.sol +++ b/contracts/XINV.sol @@ -34,11 +34,6 @@ contract xInvCore is Exponential, TokenErrorReporter { */ uint8 public decimals; - /** - * @notice Maximum fraction of interest that can be set aside for reserves - */ - uint internal constant reserveFactorMaxMantissa = 1e18; - /** * @notice Administrator for this contract */ @@ -73,6 +68,8 @@ contract xInvCore is Exponential, TokenErrorReporter { address public rewardTreasury; + uint public constant borrowIndex = 1 ether; // for compatibility with Comptroller + /** * @notice Official record of token balances for each account */ @@ -396,7 +393,7 @@ contract xInvCore is Exponential, TokenErrorReporter { emit Transfer(address(this), minter, vars.mintTokens); /* we move delegates */ - _moveDelegates(address(0), minter, uint96(vars.mintTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 + _moveDelegates(address(0), delegates[minter], uint96(vars.mintTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 /* We call the defense hook */ comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens); @@ -537,7 +534,7 @@ contract xInvCore is Exponential, TokenErrorReporter { emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); /* We move delegates */ - _moveDelegates(redeemer, address(0), uint96(vars.redeemTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 + _moveDelegates(delegates[redeemer], address(0), uint96(vars.redeemTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 /* We call the defense hook */ comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens); @@ -611,7 +608,7 @@ contract xInvCore is Exponential, TokenErrorReporter { emit Transfer(borrower, liquidator, seizeTokens); /* We move delegates to liquidator although they'll be burned in the redeemFresh call after */ - _moveDelegates(borrower, liquidator, uint96(seizeTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 + _moveDelegates(delegates[borrower], delegates[liquidator], uint96(seizeTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96 /* We call the defense hook */ comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens); @@ -779,49 +776,12 @@ contract xInvCore is Exponential, TokenErrorReporter { /// @notice The number of checkpoints for each account mapping (address => uint32) public numCheckpoints; - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - - /// @notice The EIP-712 typehash for the delegation struct used by the contract - bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - - /// @notice A record of states for signing / validating signatures - mapping (address => uint) public nonces; - /// @notice An event thats emitted when an account changes its delegate event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance); - /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to - */ - function delegate(address delegatee) public { - return _delegate(msg.sender, delegatee); - } - - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair - */ - function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { - bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); - bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); - bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); - address signatory = ecrecover(digest, v, r, s); - require(signatory != address(0), "INV::delegateBySig: invalid signature"); - require(nonce == nonces[signatory]++, "INV::delegateBySig: invalid nonce"); - require(now <= expiry, "INV::delegateBySig: signature expired"); - return _delegate(signatory, delegatee); - } - /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance @@ -914,12 +874,6 @@ contract xInvCore is Exponential, TokenErrorReporter { emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } - function getChainId() internal pure returns (uint) { - uint256 chainId; - assembly { chainId := chainid() } - return chainId; - } - function safe32(uint n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); @@ -943,7 +897,7 @@ contract TimelockEscrow { address public underlying; address public governance; address public market; - uint public duration = 14 days; + uint public duration = 10 days; mapping (address => EscrowData) public pendingWithdrawals; struct EscrowData { @@ -1056,6 +1010,15 @@ contract XINV is xInvCore { /*** User Interface ***/ + /** + * @notice Sync user delegate from INV + * @param user Address to sync + */ + function syncDelegate(address user) public { + address invDelegate = IINV(underlying).delegates(user); + _delegate(user, invDelegate); + } + /** * @notice Sender supplies assets into the market and receives cTokens in exchange * @param mintAmount The amount of the underlying asset to supply @@ -1064,12 +1027,10 @@ contract XINV is xInvCore { function mint(uint mintAmount) external returns (uint) { (uint err,) = mintInternal(mintAmount); - /* if user has no delegate, we inherit delegate from INV */ - if(delegates[msg.sender] == address(0)) { - address invDelegate = IINV(underlying).delegates(msg.sender); - if(invDelegate != address(0)) { - _delegate(msg.sender, invDelegate); - } + /* we inherit delegate from INV */ + address invDelegate = IINV(underlying).delegates(msg.sender); + if(delegates[msg.sender] != invDelegate) { + _delegate(msg.sender, invDelegate); } return err; } diff --git a/deploy/29_xINV.js b/deploy/29_xINV.js index 996a76dee..860f306e5 100644 --- a/deploy/29_xINV.js +++ b/deploy/29_xINV.js @@ -16,7 +16,7 @@ module.exports = async ({ args:[ inv, // inverse as underlying comptroller.address, - "8000000000000000", // reward per block + "6600000000000000", // reward per block gov, name, symbol, diff --git a/deployments/mainnet/XINV.json b/deployments/mainnet/XINV.json index ded0fd820..9dbb943ab 100644 --- a/deployments/mainnet/XINV.json +++ b/deployments/mainnet/XINV.json @@ -1,5 +1,5 @@ { - "address": "0x65b35d6Eb7006e0e607BC54EB2dFD459923476fE", + "address": "0x1637e4e9941D55703a7A5E7807d6aDA3f7DCD61B", "abi": [ { "inputs": [ @@ -312,36 +312,6 @@ "name": "Transfer", "type": "event" }, - { - "constant": true, - "inputs": [], - "name": "DELEGATION_TYPEHASH", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "DOMAIN_TYPEHASH", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": false, "inputs": [], @@ -549,6 +519,21 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -610,61 +595,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "delegatee", - "type": "address" - } - ], - "name": "delegate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "delegatee", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "delegateBySig", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": true, "inputs": [ @@ -880,27 +810,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": true, - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": true, "inputs": [ @@ -1055,6 +964,21 @@ "stateMutability": "view", "type": "function" }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "syncDelegate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { "constant": true, "inputs": [], @@ -1086,49 +1010,49 @@ "type": "function" } ], - "transactionHash": "0x2198de0716d23bddb8f39399036a4f37f4d30e620b5f66cf4889ba487ab0a1d8", + "transactionHash": "0x84c72410cb37f315ab38523af67528767f88388913c35730434fe1fc5279b641", "receipt": { "to": null, "from": "0x3FcB35a1CbFB6007f9BC638D388958Bc4550cB28", - "contractAddress": "0x65b35d6Eb7006e0e607BC54EB2dFD459923476fE", - "transactionIndex": 132, - "gasUsed": "4183061", - "logsBloom": "0x00000000000000000000008000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000100004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xb8830bf11c79bdd4ddd84e2cb8c1909538e83293104f1acf606082e5bbd54fb0", - "transactionHash": "0x2198de0716d23bddb8f39399036a4f37f4d30e620b5f66cf4889ba487ab0a1d8", + "contractAddress": "0x1637e4e9941D55703a7A5E7807d6aDA3f7DCD61B", + "transactionIndex": 195, + "gasUsed": "3979235", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x17c419aedc0b62a0d40c433a98ed8801931a4c60a88b8515d98686c4b5225514", + "transactionHash": "0x84c72410cb37f315ab38523af67528767f88388913c35730434fe1fc5279b641", "logs": [ { - "transactionIndex": 132, - "blockNumber": 12437327, - "transactionHash": "0x2198de0716d23bddb8f39399036a4f37f4d30e620b5f66cf4889ba487ab0a1d8", - "address": "0x65b35d6Eb7006e0e607BC54EB2dFD459923476fE", + "transactionIndex": 195, + "blockNumber": 13549472, + "transactionHash": "0x84c72410cb37f315ab38523af67528767f88388913c35730434fe1fc5279b641", + "address": "0x1637e4e9941D55703a7A5E7807d6aDA3f7DCD61B", "topics": [ "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000004dcf7407ae5c07f8681e1659f626e114a7667339", - "logIndex": 246, - "blockHash": "0xb8830bf11c79bdd4ddd84e2cb8c1909538e83293104f1acf606082e5bbd54fb0" + "logIndex": 248, + "blockHash": "0x17c419aedc0b62a0d40c433a98ed8801931a4c60a88b8515d98686c4b5225514" } ], - "blockNumber": 12437327, - "cumulativeGasUsed": "14214905", + "blockNumber": 13549472, + "cumulativeGasUsed": "16315551", "status": 1, "byzantium": true }, "args": [ "0x41D5D79431A913C4aE7d69a668ecdfE5fF9DFB68", "0x4dCf7407AE5C07f8681e1659f626E114A7667339", - "8000000000000000", + "6600000000000000", "0x926dF14a23BE491164dCF93f4c468A50ef659D5B", "xINV", "XINV", 18, "0x926dF14a23BE491164dCF93f4c468A50ef659D5B" ], - "solcInputHash": "a07ca9d40d2cb746940b5b3d6ee55692", - "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce.mod\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"underlying_\",\"type\":\"address\"},{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"comptroller_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"rewardPerBlock_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardTreasury_\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"},{\"internalType\":\"address payable\",\"name\":\"admin_\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"fromDelegate\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"toDelegate\",\"type\":\"address\"}],\"name\":\"DelegateChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegate\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"DelegateVotesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"error\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"info\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"detail\",\"type\":\"uint256\"}],\"name\":\"Failure\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"mintAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"mintTokens\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"NewAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract ComptrollerInterface\",\"name\":\"oldComptroller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contract ComptrollerInterface\",\"name\":\"newComptroller\",\"type\":\"address\"}],\"name\":\"NewComptroller\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldPendingAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"NewPendingAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldRewardPerBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newRewardPerBlock\",\"type\":\"uint256\"}],\"name\":\"NewRewardPerBlock\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRewardTreasury\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRewardTreasury\",\"type\":\"address\"}],\"name\":\"NewRewardTreasury\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract TimelockEscrow\",\"name\":\"oldTimelockEscrow\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contract TimelockEscrow\",\"name\":\"newTimelockEscrow\",\"type\":\"address\"}],\"name\":\"NewTimelockEscrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"redeemer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"DELEGATION_TYPEHASH\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"DOMAIN_TYPEHASH\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"_acceptAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"newComptroller\",\"type\":\"address\"}],\"name\":\"_setComptroller\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"_setPendingAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newRewardPerBlock\",\"type\":\"uint256\"}],\"name\":\"_setRewardPerBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRewardTreasury\",\"type\":\"address\"}],\"name\":\"_setRewardTreasury\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"contract TimelockEscrow\",\"name\":\"newTimelockEscrow\",\"type\":\"address\"}],\"name\":\"_setTimelockEscrow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"accrualBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"accrueInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOfUnderlying\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"name\":\"checkpoints\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fromBlock\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"votes\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"comptroller\",\"outputs\":[{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"delegateBySig\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegates\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"escrow\",\"outputs\":[{\"internalType\":\"contract TimelockEscrow\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exchangeRateCurrent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"exchangeRateStored\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAccountSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getCash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getCurrentVotes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getPriorVotes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isCToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"numCheckpoints\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pendingAdmin\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlying\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rewardPerBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rewardTreasury\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"liquidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"seizeTokens\",\"type\":\"uint256\"}],\"name\":\"seize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"underlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Inverse Finance\",\"methods\":{\"_acceptAdmin()\":{\"details\":\"Admin function for pending admin to accept role and update admin\",\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"_setComptroller(address)\":{\"details\":\"Admin function to set a new comptroller\",\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"_setPendingAdmin(address)\":{\"details\":\"Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\",\"params\":{\"newPendingAdmin\":\"New pending admin.\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"balanceOf(address)\":{\"params\":{\"owner\":\"The address of the account to query\"},\"return\":\"The number of tokens owned by `owner`\"},\"balanceOfUnderlying(address)\":{\"params\":{\"owner\":\"The address of the account to query\"},\"return\":\"The amount of underlying owned by `owner`\"},\"constructor\":{\"params\":{\"admin_\":\"Address of the administrator of this token\",\"comptroller_\":\"The address of the Comptroller\",\"decimals_\":\"ERC-20 decimal precision of this token\",\"name_\":\"ERC-20 name of this token\",\"symbol_\":\"ERC-20 symbol of this token\",\"underlying_\":\"The address of the underlying asset\"}},\"delegate(address)\":{\"params\":{\"delegatee\":\"The address to delegate votes to\"}},\"delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)\":{\"params\":{\"delegatee\":\"The address to delegate votes to\",\"expiry\":\"The time at which to expire the signature\",\"nonce\":\"The contract state required to match the signature\",\"r\":\"Half of the ECDSA signature pair\",\"s\":\"Half of the ECDSA signature pair\",\"v\":\"The recovery byte of the signature\"}},\"exchangeRateCurrent()\":{\"return\":\"Calculated exchange rate scaled by 1e18\"},\"exchangeRateStored()\":{\"return\":\"Calculated exchange rate scaled by 1e18\"},\"getAccountSnapshot(address)\":{\"details\":\"This is used by comptroller to more efficiently perform liquidity checks.\",\"params\":{\"account\":\"Address of the account to snapshot\"},\"return\":\"(possible error, token balance, borrow balance, exchange rate mantissa)\"},\"getCash()\":{\"return\":\"The quantity of underlying asset owned by this contract\"},\"getCurrentVotes(address)\":{\"params\":{\"account\":\"The address to get votes balance\"},\"return\":\"The number of current votes for `account`\"},\"getPriorVotes(address,uint256)\":{\"details\":\"Block number must be a finalized block or else this function will revert to prevent misinformation.\",\"params\":{\"account\":\"The address of the account to check\",\"blockNumber\":\"The block number to get the vote balance at\"},\"return\":\"The number of votes the account had as of the given block\"},\"mint(uint256)\":{\"params\":{\"mintAmount\":\"The amount of the underlying asset to supply\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"redeem(uint256)\":{\"params\":{\"redeemTokens\":\"The number of cTokens to redeem into underlying\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"redeemUnderlying(uint256)\":{\"params\":{\"redeemAmount\":\"The amount of underlying to redeem\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"seize(address,address,uint256)\":{\"details\":\"Will fail unless called by another cToken during the process of liquidation. Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\",\"params\":{\"borrower\":\"The account having collateral seized\",\"liquidator\":\"The account receiving seized collateral\",\"seizeTokens\":\"The number of cTokens to seize\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"}},\"title\":\"xINV contract\"},\"userdoc\":{\"methods\":{\"_acceptAdmin()\":{\"notice\":\"Accepts transfer of admin rights. msg.sender must be pendingAdmin\"},\"_setComptroller(address)\":{\"notice\":\"Sets a new comptroller for the market\"},\"_setPendingAdmin(address)\":{\"notice\":\"Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\"},\"balanceOf(address)\":{\"notice\":\"Get the token balance of the `owner`\"},\"balanceOfUnderlying(address)\":{\"notice\":\"Get the underlying balance of the `owner`\"},\"constructor\":\"Construct the xINV market\",\"delegate(address)\":{\"notice\":\"Delegate votes from `msg.sender` to `delegatee`\"},\"delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)\":{\"notice\":\"Delegates votes from signatory to `delegatee`\"},\"exchangeRateStored()\":{\"notice\":\"Calculates the exchange rate from the underlying to the CToken\"},\"getAccountSnapshot(address)\":{\"notice\":\"Get a snapshot of the account's balances, and the cached exchange rate\"},\"getCash()\":{\"notice\":\"Get cash balance of this cToken in the underlying asset\"},\"getCurrentVotes(address)\":{\"notice\":\"Gets the current votes balance for `account`\"},\"getPriorVotes(address,uint256)\":{\"notice\":\"Determine the prior number of votes for an account as of a block number\"},\"mint(uint256)\":{\"notice\":\"Sender supplies assets into the market and receives cTokens in exchange\"},\"redeem(uint256)\":{\"notice\":\"Sender redeems cTokens in exchange for the underlying asset\"},\"redeemUnderlying(uint256)\":{\"notice\":\"Sender redeems cTokens in exchange for a specified amount of underlying asset\"},\"seize(address,address,uint256)\":{\"notice\":\"Transfers collateral tokens (this market) to the liquidator.\"}},\"notice\":\"wraps INV token\"}},\"settings\":{\"compilationTarget\":{\"contracts/XINV.sol\":\"XINV\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CarefulMath.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title Careful Math\\n * @author Compound\\n * @notice Derived from OpenZeppelin's SafeMath library\\n * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol\\n */\\ncontract CarefulMath {\\n\\n /**\\n * @dev Possible error codes that we can return\\n */\\n enum MathError {\\n NO_ERROR,\\n DIVISION_BY_ZERO,\\n INTEGER_OVERFLOW,\\n INTEGER_UNDERFLOW\\n }\\n\\n /**\\n * @dev Multiplies two numbers, returns an error on overflow.\\n */\\n function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (a == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n uint c = a * b;\\n\\n if (c / a != b) {\\n return (MathError.INTEGER_OVERFLOW, 0);\\n } else {\\n return (MathError.NO_ERROR, c);\\n }\\n }\\n\\n /**\\n * @dev Integer division of two numbers, truncating the quotient.\\n */\\n function divUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (b == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n\\n return (MathError.NO_ERROR, a / b);\\n }\\n\\n /**\\n * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).\\n */\\n function subUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (b <= a) {\\n return (MathError.NO_ERROR, a - b);\\n } else {\\n return (MathError.INTEGER_UNDERFLOW, 0);\\n }\\n }\\n\\n /**\\n * @dev Adds two numbers, returns an error on overflow.\\n */\\n function addUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n uint c = a + b;\\n\\n if (c >= a) {\\n return (MathError.NO_ERROR, c);\\n } else {\\n return (MathError.INTEGER_OVERFLOW, 0);\\n }\\n }\\n\\n /**\\n * @dev add a and b and then subtract c\\n */\\n function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {\\n (MathError err0, uint sum) = addUInt(a, b);\\n\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, 0);\\n }\\n\\n return subUInt(sum, c);\\n }\\n}\",\"keccak256\":\"0x0647348f27e41d22555d99eebd217dee02a4d737df6accd7cce5347a7487c7de\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ncontract ComptrollerInterface {\\n /// @notice Indicator that this is a Comptroller contract (for inspection)\\n bool public constant isComptroller = true;\\n\\n /*** Assets You Are In ***/\\n\\n function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);\\n function exitMarket(address cToken) external returns (uint);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);\\n function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;\\n\\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);\\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;\\n\\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);\\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint repayAmount) external returns (uint);\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint repayAmount,\\n uint borrowerIndex) external;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint repayAmount) external returns (uint);\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint repayAmount,\\n uint seizeTokens) external;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint seizeTokens) external returns (uint);\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint seizeTokens) external;\\n\\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);\\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint repayAmount) external view returns (uint, uint);\\n}\\n\",\"keccak256\":\"0xede7670d2dd7b25d0187aecd2c28b7b5ca7d7c1bdac144fbedecf5d4bdd92a6b\"},\"contracts/EIP20Interface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title ERC 20 Token Standard Interface\\n * https://eips.ethereum.org/EIPS/eip-20\\n */\\ninterface EIP20Interface {\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n\\n /**\\n * @notice Get the total number of tokens in circulation\\n * @return The supply of tokens\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @notice Gets the balance of the specified address\\n * @param owner The address from which the balance will be retrieved\\n * @return The balance\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n * @return Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Transfer `amount` tokens from `src` to `dst`\\n * @param src The address of the source account\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n * @return Whether or not the transfer succeeded\\n */\\n function transferFrom(address src, address dst, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Approve `spender` to transfer up to `amount` from `src`\\n * @dev This will overwrite the approval amount for `spender`\\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\\n * @param spender The address of the account which may transfer tokens\\n * @param amount The number of tokens that are approved (-1 means infinite)\\n * @return Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Get the current allowance from `owner` for `spender`\\n * @param owner The address of the account which owns the tokens to be spent\\n * @param spender The address of the account which may transfer tokens\\n * @return The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender) external view returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n}\\n\",\"keccak256\":\"0xfd8ed2eac6d0b4d9ee6b32628ba68bae17544b66f190a5f7ce0c6ad024579dc8\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title EIP20NonStandardInterface\\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\ninterface EIP20NonStandardInterface {\\n\\n /**\\n * @notice Get the total number of tokens in circulation\\n * @return The supply of tokens\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @notice Gets the balance of the specified address\\n * @param owner The address from which the balance will be retrieved\\n * @return The balance\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n ///\\n /// !!!!!!!!!!!!!!\\n /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification\\n /// !!!!!!!!!!!!!!\\n ///\\n\\n /**\\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n */\\n function transfer(address dst, uint256 amount) external;\\n\\n ///\\n /// !!!!!!!!!!!!!!\\n /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification\\n /// !!!!!!!!!!!!!!\\n ///\\n\\n /**\\n * @notice Transfer `amount` tokens from `src` to `dst`\\n * @param src The address of the source account\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n */\\n function transferFrom(address src, address dst, uint256 amount) external;\\n\\n /**\\n * @notice Approve `spender` to transfer up to `amount` from `src`\\n * @dev This will overwrite the approval amount for `spender`\\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\\n * @param spender The address of the account which may transfer tokens\\n * @param amount The number of tokens that are approved\\n * @return Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Get the current allowance from `owner` for `spender`\\n * @param owner The address of the account which owns the tokens to be spent\\n * @param spender The address of the account which may transfer tokens\\n * @return The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender) external view returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n}\\n\",\"keccak256\":\"0x9719f12e4b80b51147ac195553a198cf8b0c516e7e4d04fc324a23ed15cbafb2\"},\"contracts/ErrorReporter.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ncontract ComptrollerErrorReporter {\\n enum Error {\\n NO_ERROR,\\n UNAUTHORIZED,\\n COMPTROLLER_MISMATCH,\\n INSUFFICIENT_SHORTFALL,\\n INSUFFICIENT_LIQUIDITY,\\n INVALID_CLOSE_FACTOR,\\n INVALID_COLLATERAL_FACTOR,\\n INVALID_LIQUIDATION_INCENTIVE,\\n MARKET_NOT_ENTERED, // no longer possible\\n MARKET_NOT_LISTED,\\n MARKET_ALREADY_LISTED,\\n MATH_ERROR,\\n NONZERO_BORROW_BALANCE,\\n PRICE_ERROR,\\n REJECTION,\\n SNAPSHOT_ERROR,\\n TOO_MANY_ASSETS,\\n TOO_MUCH_REPAY\\n }\\n\\n enum FailureInfo {\\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\\n ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,\\n EXIT_MARKET_BALANCE_OWED,\\n EXIT_MARKET_REJECTION,\\n SET_CLOSE_FACTOR_OWNER_CHECK,\\n SET_CLOSE_FACTOR_VALIDATION,\\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\\n SET_COLLATERAL_FACTOR_NO_EXISTS,\\n SET_COLLATERAL_FACTOR_VALIDATION,\\n SET_COLLATERAL_FACTOR_WITHOUT_PRICE,\\n SET_IMPLEMENTATION_OWNER_CHECK,\\n SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,\\n SET_LIQUIDATION_INCENTIVE_VALIDATION,\\n SET_MAX_ASSETS_OWNER_CHECK,\\n SET_PENDING_ADMIN_OWNER_CHECK,\\n SET_PENDING_IMPLEMENTATION_OWNER_CHECK,\\n SET_PRICE_ORACLE_OWNER_CHECK,\\n SUPPORT_MARKET_EXISTS,\\n SUPPORT_MARKET_OWNER_CHECK,\\n SET_PAUSE_GUARDIAN_OWNER_CHECK\\n }\\n\\n /**\\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\\n **/\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\\n */\\n function fail(Error err, FailureInfo info) internal returns (uint) {\\n emit Failure(uint(err), uint(info), 0);\\n\\n return uint(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\\n emit Failure(uint(err), uint(info), opaqueError);\\n\\n return uint(err);\\n }\\n}\\n\\ncontract TokenErrorReporter {\\n enum Error {\\n NO_ERROR,\\n UNAUTHORIZED,\\n BAD_INPUT,\\n COMPTROLLER_REJECTION,\\n COMPTROLLER_CALCULATION_ERROR,\\n INTEREST_RATE_MODEL_ERROR,\\n INVALID_ACCOUNT_PAIR,\\n INVALID_CLOSE_AMOUNT_REQUESTED,\\n INVALID_COLLATERAL_FACTOR,\\n MATH_ERROR,\\n MARKET_NOT_FRESH,\\n MARKET_NOT_LISTED,\\n TOKEN_INSUFFICIENT_ALLOWANCE,\\n TOKEN_INSUFFICIENT_BALANCE,\\n TOKEN_INSUFFICIENT_CASH,\\n TOKEN_TRANSFER_IN_FAILED,\\n TOKEN_TRANSFER_OUT_FAILED\\n }\\n\\n /*\\n * Note: FailureInfo (but not Error) is kept in alphabetical order\\n * This is because FailureInfo grows significantly faster, and\\n * the order of Error has some meaning, while the order of FailureInfo\\n * is entirely arbitrary.\\n */\\n enum FailureInfo {\\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\\n ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n BORROW_ACCRUE_INTEREST_FAILED,\\n BORROW_CASH_NOT_AVAILABLE,\\n BORROW_FRESHNESS_CHECK,\\n BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n BORROW_MARKET_NOT_LISTED,\\n BORROW_COMPTROLLER_REJECTION,\\n LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,\\n LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,\\n LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,\\n LIQUIDATE_COMPTROLLER_REJECTION,\\n LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,\\n LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,\\n LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,\\n LIQUIDATE_FRESHNESS_CHECK,\\n LIQUIDATE_LIQUIDATOR_IS_BORROWER,\\n LIQUIDATE_REPAY_BORROW_FRESH_FAILED,\\n LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,\\n LIQUIDATE_SEIZE_TOO_MUCH,\\n MINT_ACCRUE_INTEREST_FAILED,\\n MINT_COMPTROLLER_REJECTION,\\n MINT_EXCHANGE_CALCULATION_FAILED,\\n MINT_EXCHANGE_RATE_READ_FAILED,\\n MINT_FRESHNESS_CHECK,\\n MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n MINT_TRANSFER_IN_FAILED,\\n MINT_TRANSFER_IN_NOT_POSSIBLE,\\n REDEEM_ACCRUE_INTEREST_FAILED,\\n REDEEM_COMPTROLLER_REJECTION,\\n REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,\\n REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n REDEEM_EXCHANGE_RATE_READ_FAILED,\\n REDEEM_FRESHNESS_CHECK,\\n REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n REDEEM_TRANSFER_OUT_NOT_POSSIBLE,\\n REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,\\n REDUCE_RESERVES_ADMIN_CHECK,\\n REDUCE_RESERVES_CASH_NOT_AVAILABLE,\\n REDUCE_RESERVES_FRESH_CHECK,\\n REDUCE_RESERVES_VALIDATION,\\n REPAY_BEHALF_ACCRUE_INTEREST_FAILED,\\n REPAY_BORROW_ACCRUE_INTEREST_FAILED,\\n REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_COMPTROLLER_REJECTION,\\n REPAY_BORROW_FRESHNESS_CHECK,\\n REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,\\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\\n SET_COLLATERAL_FACTOR_VALIDATION,\\n SET_COMPTROLLER_OWNER_CHECK,\\n SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,\\n SET_INTEREST_RATE_MODEL_FRESH_CHECK,\\n SET_INTEREST_RATE_MODEL_OWNER_CHECK,\\n SET_MAX_ASSETS_OWNER_CHECK,\\n SET_ORACLE_MARKET_NOT_LISTED,\\n SET_PENDING_ADMIN_OWNER_CHECK,\\n SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,\\n SET_RESERVE_FACTOR_ADMIN_CHECK,\\n SET_RESERVE_FACTOR_FRESH_CHECK,\\n SET_RESERVE_FACTOR_BOUNDS_CHECK,\\n TRANSFER_COMPTROLLER_REJECTION,\\n TRANSFER_NOT_ALLOWED,\\n TRANSFER_NOT_ENOUGH,\\n TRANSFER_TOO_MUCH,\\n ADD_RESERVES_ACCRUE_INTEREST_FAILED,\\n ADD_RESERVES_FRESH_CHECK,\\n ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE\\n }\\n\\n /**\\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\\n **/\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\\n */\\n function fail(Error err, FailureInfo info) internal returns (uint) {\\n emit Failure(uint(err), uint(info), 0);\\n\\n return uint(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\\n emit Failure(uint(err), uint(info), opaqueError);\\n\\n return uint(err);\\n }\\n}\",\"keccak256\":\"0x5179afb1071c0fd555e5c1f1d2565f72dbe1740cc3dd02f6e52037f150afc5c9\"},\"contracts/Exponential.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author Compound\\n * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract Exponential is CarefulMath, ExponentialNoError {\\n /**\\n * @dev Creates an exponential from numerator and denominator values.\\n * Note: Returns an error if (`num` * 10e18) > MAX_INT,\\n * or if `denom` is zero.\\n */\\n function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n (MathError err1, uint rational) = divUInt(scaledNumerator, denom);\\n if (err1 != MathError.NO_ERROR) {\\n return (err1, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: rational}));\\n }\\n\\n /**\\n * @dev Adds two exponentials, returning a new exponential.\\n */\\n function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);\\n\\n return (error, Exp({mantissa: result}));\\n }\\n\\n /**\\n * @dev Subtracts two exponentials, returning a new exponential.\\n */\\n function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);\\n\\n return (error, Exp({mantissa: result}));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, returning a new Exp.\\n */\\n function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory product) = mulScalar(a, scalar);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return (MathError.NO_ERROR, truncate(product));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory product) = mulScalar(a, scalar);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return addUInt(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Divide an Exp by a scalar, returning a new Exp.\\n */\\n function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));\\n }\\n\\n /**\\n * @dev Divide a scalar by an Exp, returning a new Exp.\\n */\\n function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {\\n /*\\n We are doing this as:\\n getExp(mulUInt(expScale, scalar), divisor.mantissa)\\n\\n How it works:\\n Exp = a / b;\\n Scalar = s;\\n `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`\\n */\\n (MathError err0, uint numerator) = mulUInt(expScale, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n return getExp(numerator, divisor.mantissa);\\n }\\n\\n /**\\n * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.\\n */\\n function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return (MathError.NO_ERROR, truncate(fraction));\\n }\\n\\n /**\\n * @dev Multiplies two exponentials, returning a new exponential.\\n */\\n function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n\\n (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n // We add half the scale before dividing so that we get rounding instead of truncation.\\n // See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717\\n // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.\\n (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);\\n if (err1 != MathError.NO_ERROR) {\\n return (err1, Exp({mantissa: 0}));\\n }\\n\\n (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);\\n // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.\\n assert(err2 == MathError.NO_ERROR);\\n\\n return (MathError.NO_ERROR, Exp({mantissa: product}));\\n }\\n\\n /**\\n * @dev Multiplies two exponentials given their mantissas, returning a new exponential.\\n */\\n function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {\\n return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));\\n }\\n\\n /**\\n * @dev Multiplies three exponentials, returning a new exponential.\\n */\\n function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {\\n (MathError err, Exp memory ab) = mulExp(a, b);\\n if (err != MathError.NO_ERROR) {\\n return (err, ab);\\n }\\n return mulExp(ab, c);\\n }\\n\\n /**\\n * @dev Divides two exponentials, returning a new exponential.\\n * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,\\n * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)\\n */\\n function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x6ff054d65a0289dbb43c9f437d6909f9cf1207c9b8f984b3cb8e97a9de76a434\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author Compound\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x7cb184b7cee71a5e707053dfba7eebbd46f11974004028100510ccce19b6694d\"},\"contracts/Governance/IINV.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ninterface IINV {\\n function balanceOf(address) external view returns (uint);\\n function transfer(address,uint) external returns (bool);\\n function delegates(address) external view returns (address);\\n function delegate(address) external;\\n}\",\"keccak256\":\"0x970a0244d4ce1448e26ed8fcacd7959e9a676a786e3e7f29a62acca590f1fcf9\"},\"contracts/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\\n// Subject to the MIT license.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, errorMessage);\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot underflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction underflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot underflow.\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, errorMessage);\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers.\\n * Reverts on division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers.\\n * Reverts with custom message on division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x6653e37ff57a02b7b7f20199bb0fd5685756ced19a67f53328b42c9d2167ffd2\"},\"contracts/XINV.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Governance/IINV.sol\\\";\\n/**\\n * @title xINV Core contract\\n * @notice Abstract base for xINV\\n * @author Inverse Finance\\n */\\ncontract xInvCore is Exponential, TokenErrorReporter {\\n\\n /**\\n * @dev Guard variable for re-entrancy checks\\n */\\n bool internal _notEntered;\\n\\n /**\\n * @notice EIP-20 token name for this token\\n */\\n string public name;\\n\\n /**\\n * @notice EIP-20 token symbol for this token\\n */\\n string public symbol;\\n\\n /**\\n * @notice EIP-20 token decimals for this token\\n */\\n uint8 public decimals;\\n\\n /**\\n * @notice Maximum fraction of interest that can be set aside for reserves\\n */\\n uint internal constant reserveFactorMaxMantissa = 1e18;\\n\\n /**\\n * @notice Administrator for this contract\\n */\\n address payable public admin;\\n\\n /**\\n * @notice Pending administrator for this contract\\n */\\n address payable public pendingAdmin;\\n\\n /**\\n * @notice Contract which oversees inter-cToken operations\\n */\\n ComptrollerInterface public comptroller;\\n\\n /**\\n * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)\\n */\\n uint internal initialExchangeRateMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint public accrualBlockNumber;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint public totalSupply;\\n\\n uint public rewardPerBlock;\\n\\n address public rewardTreasury;\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping (address => uint) internal accountTokens;\\n\\n /**\\n * @notice Indicator that this is a CToken contract (for inspection)\\n */\\n bool public constant isCToken = true;\\n\\n /*** Market Events ***/\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address minter, uint mintAmount, uint mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);\\n\\n /*** Admin Events ***/\\n\\n /**\\n * @notice Event emitted when pendingAdmin is changed\\n */\\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\\n\\n /**\\n * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\\n */\\n event NewAdmin(address oldAdmin, address newAdmin);\\n\\n /**\\n * @notice Event emitted when comptroller is changed\\n */\\n event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);\\n\\n /**\\n * @notice Event emitted when reward treasury is changed\\n */\\n event NewRewardTreasury(address oldRewardTreasury, address newRewardTreasury);\\n\\n /**\\n * @notice Event emitted when reward per block is changed\\n */\\n event NewRewardPerBlock(uint oldRewardPerBlock, uint newRewardPerBlock);\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint amount);\\n\\n /**\\n * @notice Failure event\\n */\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @notice Initialize the money market\\n * @param comptroller_ The address of the Comptroller\\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\\n * @param name_ EIP-20 name of this token\\n * @param symbol_ EIP-20 symbol of this token\\n * @param decimals_ EIP-20 decimal precision of this token\\n */\\n function initialize(ComptrollerInterface comptroller_,\\n uint initialExchangeRateMantissa_,\\n uint rewardPerBlock_,\\n address rewardTreasury_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_) internal {\\n require(msg.sender == admin, \\\"only admin may initialize the market\\\");\\n require(accrualBlockNumber == 0, \\\"market may only be initialized once\\\");\\n\\n // Set initial exchange rate\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"initial exchange rate must be greater than zero.\\\");\\n\\n // Set the comptroller\\n uint err = _setComptroller(comptroller_);\\n require(err == uint(Error.NO_ERROR), \\\"setting comptroller failed\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n accrualBlockNumber = getBlockNumber();\\n rewardPerBlock = rewardPerBlock_;\\n rewardTreasury = rewardTreasury_;\\n\\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\\n _notEntered = true;\\n }\\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 return accountTokens[owner];\\n }\\n\\n /**\\n * @notice Get the underlying balance of the `owner`\\n * @param owner The address of the account to query\\n * @return The amount of underlying owned by `owner`\\n */\\n function balanceOfUnderlying(address owner) external returns (uint) {\\n Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});\\n (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);\\n require(mErr == MathError.NO_ERROR, \\\"balance could not be calculated\\\");\\n return balance;\\n }\\n\\n /**\\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\\n * @param account Address of the account to snapshot\\n * @return (possible error, token balance, borrow balance, exchange rate mantissa)\\n */\\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {\\n uint cTokenBalance = accountTokens[account];\\n uint exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (uint(Error.NO_ERROR), cTokenBalance, 0, exchangeRateMantissa);\\n }\\n\\n /**\\n * @dev Function to simply retrieve block number\\n * This exists mainly for inheriting test contracts to stub this result.\\n */\\n function getBlockNumber() internal view returns (uint) {\\n return block.number;\\n }\\n\\n /**\\n * @return Calculated exchange rate scaled by 1e18\\n */\\n function exchangeRateCurrent() public nonReentrant returns (uint) {\\n require(accrueInterest() == uint(Error.NO_ERROR), \\\"accrue interest failed\\\");\\n return exchangeRateStored();\\n }\\n\\n /**\\n * @notice Calculates the exchange rate from the underlying to the CToken\\n * @return Calculated exchange rate scaled by 1e18\\n */\\n function exchangeRateStored() public view returns (uint) {\\n (MathError err, uint result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"exchangeRateStored: exchangeRateStoredInternal failed\\\");\\n return result;\\n }\\n\\n /**\\n * @notice Calculates the exchange rate from the underlying to the CToken\\n * @return (error code, calculated exchange rate scaled by 1e18)\\n */\\n function exchangeRateStoredInternal() internal view returns (MathError, uint) {\\n uint _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n /*\\n * If there are no tokens minted:\\n * exchangeRate = initialExchangeRate\\n */\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n /*\\n * Otherwise:\\n * exchangeRate = totalCash / totalSupply\\n */\\n uint totalCash = getCashPrior();\\n Exp memory exchangeRate;\\n MathError mathErr;\\n\\n (mathErr, exchangeRate) = getExp(totalCash, _totalSupply);\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n /**\\n * @notice Get cash balance of this cToken in the underlying asset\\n * @return The quantity of underlying asset owned by this contract\\n */\\n function getCash() external view returns (uint) {\\n return getCashPrior();\\n }\\n\\n // brings rewards from treasury into this contract\\n function accrueInterest() public returns (uint) {\\n /* Remember the initial block number */\\n uint currentBlockNumber = getBlockNumber();\\n uint accrualBlockNumberPrior = accrualBlockNumber;\\n\\n /* Short-circuit accumulating 0 interest */\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint(Error.NO_ERROR);\\n }\\n\\n /* Calculate the number of blocks elapsed since the last accrual */\\n (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);\\n require(mathErr == MathError.NO_ERROR, \\\"could not calculate block delta\\\");\\n \\n /* Calculate accumulated reward amount */\\n uint reward;\\n \\n (mathErr, reward) = mulUInt(rewardPerBlock, blockDelta);\\n require(mathErr == MathError.NO_ERROR, \\\"could not calculate reward\\\");\\n\\n if(totalSupply > 0 && rewardTreasury != address(0) && canTransferIn(rewardTreasury, reward)) {\\n doTransferIn(rewardTreasury, reward);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n accrualBlockNumber = currentBlockNumber;\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Sender supplies assets into the market and receives cTokens in exchange\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\\n */\\n function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\\n return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);\\n }\\n // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint exchangeRateMantissa;\\n uint mintTokens;\\n uint totalSupplyNew;\\n uint accountTokensNew;\\n uint actualMintAmount;\\n }\\n\\n /**\\n * @notice User supplies assets into the market and receives cTokens in exchange\\n * @param minter The address of the account which is supplying the assets\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\\n */\\n function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {\\n /* Fail if mint not allowed */\\n uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);\\n if (allowed != 0) {\\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);\\n }\\n\\n MintLocalVars memory vars;\\n\\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /*\\n * We call `doTransferIn` for the minter and the mintAmount.\\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\\n * `doTransferIn` reverts if anything goes wrong, since we can't be sure if\\n * side-effects occurred. The function returns the amount actually transferred,\\n * in case of a fee. On success, the cToken holds an additional `actualMintAmount`\\n * of cash.\\n */\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n /*\\n * We get the current exchange rate and calculate the number of cTokens to be minted:\\n * mintTokens = actualMintAmount / exchangeRate\\n */\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_EXCHANGE_CALCULATION_FAILED\\\");\\n\\n /*\\n * We calculate the new total supply of cTokens and minter token balance, checking for overflow:\\n * totalSupplyNew = totalSupply + mintTokens\\n * accountTokensNew = accountTokens[minter] + mintTokens\\n */\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED\\\");\\n require(vars.totalSupplyNew < 2**96, \\\"MINT_NEW_TOTAL_SUPPLY_OVER_CAPACITY\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED\\\");\\n\\n /* We write previously calculated values into storage */\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = vars.accountTokensNew;\\n\\n /* We emit a Mint event, and a Transfer event */\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n /* we move delegates */\\n _moveDelegates(address(0), minter, uint96(vars.mintTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);\\n\\n return (uint(Error.NO_ERROR), vars.actualMintAmount);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for the underlying asset\\n * @param redeemTokens The number of cTokens to redeem into underlying\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemInternal(uint redeemTokens, bool useEscrow) internal nonReentrant returns (uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\\n return redeemFresh(msg.sender, redeemTokens, 0, useEscrow);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\\n * @param redeemAmount The amount of underlying to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemUnderlyingInternal(uint redeemAmount, bool useEscrow) internal nonReentrant returns (uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\\n return redeemFresh(msg.sender, 0, redeemAmount, useEscrow);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint exchangeRateMantissa;\\n uint redeemTokens;\\n uint redeemAmount;\\n uint totalSupplyNew;\\n uint accountTokensNew;\\n }\\n\\n /**\\n * @notice User redeems cTokens in exchange for the underlying asset\\n * @param redeemer The address of the account which is redeeming the tokens\\n * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn, bool useEscrow) internal returns (uint) {\\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \\\"one of redeemTokensIn or redeemAmountIn must be zero\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n /* exchangeRate = invoke Exchange Rate Stored() */\\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));\\n }\\n\\n /* If redeemTokensIn > 0: */\\n if (redeemTokensIn > 0) {\\n /*\\n * We calculate the exchange rate and the amount of underlying to be redeemed:\\n * redeemTokens = redeemTokensIn\\n * redeemAmount = redeemTokensIn x exchangeRateCurrent\\n */\\n vars.redeemTokens = redeemTokensIn;\\n\\n (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n } else {\\n /*\\n * We get the current exchange rate and calculate the amount to be redeemed:\\n * redeemTokens = redeemAmountIn / exchangeRate\\n * redeemAmount = redeemAmountIn\\n */\\n\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n }\\n\\n /* Fail if redeem not allowed */\\n uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);\\n if (allowed != 0) {\\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);\\n }\\n\\n /*\\n * We calculate the new total supply and redeemer balance, checking for underflow:\\n * totalSupplyNew = totalSupply - redeemTokens\\n * accountTokensNew = accountTokens[redeemer] - redeemTokens\\n */\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n /* Fail gracefully if protocol has insufficient cash */\\n if (getCashPrior() < vars.redeemAmount) {\\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /*\\n * We invoke doTransferOut for the redeemer and the redeemAmount.\\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\\n * On success, the cToken has redeemAmount less of cash.\\n * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\\n */\\n doTransferOut(redeemer, vars.redeemAmount, useEscrow);\\n\\n /* We write previously calculated values into storage */\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[redeemer] = vars.accountTokensNew;\\n\\n /* We emit a Transfer event, and a Redeem event */\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n /* We move delegates */\\n _moveDelegates(redeemer, address(0), uint96(vars.redeemTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Transfers collateral tokens (this market) to the liquidator.\\n * @dev Will fail unless called by another cToken during the process of liquidation.\\n * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\\n * @param liquidator The account receiving seized collateral\\n * @param borrower The account having collateral seized\\n * @param seizeTokens The number of cTokens to seize\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n /**\\n * @notice Transfers collateral tokens (this market) to the liquidator.\\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.\\n * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.\\n * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)\\n * @param liquidator The account receiving seized collateral\\n * @param borrower The account having collateral seized\\n * @param seizeTokens The number of cTokens to seize\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {\\n /* Fail if seize not allowed */\\n uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);\\n if (allowed != 0) {\\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);\\n }\\n\\n /* Fail if borrower = liquidator */\\n if (borrower == liquidator) {\\n return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);\\n }\\n\\n MathError mathErr;\\n uint borrowerTokensNew;\\n uint liquidatorTokensNew;\\n\\n /*\\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\\n */\\n (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));\\n }\\n\\n (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /* We write the previously calculated values into storage */\\n accountTokens[borrower] = borrowerTokensNew;\\n accountTokens[liquidator] = liquidatorTokensNew;\\n\\n /* Emit a Transfer event */\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n /* We move delegates to liquidator although they'll be burned in the redeemFresh call after */\\n _moveDelegates(borrower, liquidator, uint96(seizeTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);\\n\\n // Auto-redeem liquidator and skip escrow (cast liquidator to payable)\\n redeemFresh(address(uint160(liquidator)), seizeTokens, 0, false);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n\\n /*** Admin Functions ***/\\n\\n /**\\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\\n * @param newPendingAdmin New pending admin.\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {\\n // Check caller = admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);\\n }\\n\\n // Save current value, if any, for inclusion in log\\n address oldPendingAdmin = pendingAdmin;\\n\\n // Store pendingAdmin with value newPendingAdmin\\n pendingAdmin = newPendingAdmin;\\n\\n // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\\n * @dev Admin function for pending admin to accept role and update admin\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _acceptAdmin() external returns (uint) {\\n // Check caller is pendingAdmin and pendingAdmin \\u2260 address(0)\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);\\n }\\n\\n // Save current values for inclusion in log\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n // Store admin with value pendingAdmin\\n admin = pendingAdmin;\\n\\n // Clear the pending value\\n pendingAdmin = address(0);\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Sets a new comptroller for the market\\n * @dev Admin function to set a new comptroller\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n // Ensure invoke comptroller.isComptroller() returns true\\n require(newComptroller.isComptroller(), \\\"marker method returned false\\\");\\n\\n // Set market's comptroller to newComptroller\\n comptroller = newComptroller;\\n\\n // Emit NewComptroller(oldComptroller, newComptroller)\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n function _setRewardTreasury(address newRewardTreasury) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n \\n address oldRewardTreasury = rewardTreasury;\\n rewardTreasury = newRewardTreasury; // it's acceptable to set it as address(0)\\n\\n emit NewRewardTreasury(oldRewardTreasury, newRewardTreasury);\\n }\\n\\n function _setRewardPerBlock(uint newRewardPerBlock) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n\\n uint oldRewardPerBlock = rewardPerBlock;\\n rewardPerBlock = newRewardPerBlock; // it's acceptable to set it as 0\\n\\n emit NewRewardPerBlock(oldRewardPerBlock, newRewardPerBlock);\\n\\n }\\n\\n /*** Safe Token ***/\\n\\n /**\\n * @notice Gets balance of this contract in terms of the underlying\\n * @dev This excludes the value of the current message, if any\\n * @return The quantity of underlying owned by this contract\\n */\\n function getCashPrior() internal view returns (uint);\\n\\n /**\\n * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.\\n * This may revert due to insufficient balance or insufficient allowance.\\n */\\n function doTransferIn(address from, uint amount) internal returns (uint);\\n\\n function canTransferIn(address from, uint amount) internal view returns (bool);\\n \\n /**\\n * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.\\n * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.\\n * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.\\n */\\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal;\\n\\n\\n /*** Reentrancy Guard ***/\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n */\\n modifier nonReentrant() {\\n require(_notEntered, \\\"re-entered\\\");\\n _notEntered = false;\\n _;\\n _notEntered = true; // get a gas-refund post-Istanbul\\n }\\n\\n /*** Delegation ***/\\n \\n /// @notice A record of each accounts delegate\\n mapping (address => address) public delegates;\\n\\n /// @notice A checkpoint for marking number of votes from a given block\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 votes;\\n }\\n\\n /// @notice A record of votes checkpoints for each account, by index\\n mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;\\n\\n /// @notice The number of checkpoints for each account\\n mapping (address => uint32) public numCheckpoints;\\n\\n /// @notice The EIP-712 typehash for the contract's domain\\n bytes32 public constant DOMAIN_TYPEHASH = keccak256(\\\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\\\");\\n\\n /// @notice The EIP-712 typehash for the delegation struct used by the contract\\n bytes32 public constant DELEGATION_TYPEHASH = keccak256(\\\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\\\");\\n\\n /// @notice A record of states for signing / validating signatures\\n mapping (address => uint) public nonces;\\n\\n /// @notice An event thats emitted when an account changes its delegate\\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\\n\\n /// @notice An event thats emitted when a delegate account's vote balance changes\\n event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);\\n\\n /**\\n * @notice Delegate votes from `msg.sender` to `delegatee`\\n * @param delegatee The address to delegate votes to\\n */\\n function delegate(address delegatee) public {\\n return _delegate(msg.sender, delegatee);\\n }\\n\\n /**\\n * @notice Delegates votes from signatory to `delegatee`\\n * @param delegatee The address to delegate votes to\\n * @param nonce The contract state required to match the signature\\n * @param expiry The time at which to expire the signature\\n * @param v The recovery byte of the signature\\n * @param r Half of the ECDSA signature pair\\n * @param s Half of the ECDSA signature pair\\n */\\n function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public {\\n bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));\\n bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));\\n bytes32 digest = keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n address signatory = ecrecover(digest, v, r, s);\\n require(signatory != address(0), \\\"INV::delegateBySig: invalid signature\\\");\\n require(nonce == nonces[signatory]++, \\\"INV::delegateBySig: invalid nonce\\\");\\n require(now <= expiry, \\\"INV::delegateBySig: signature expired\\\");\\n return _delegate(signatory, delegatee);\\n }\\n\\n /**\\n * @notice Gets the current votes balance for `account`\\n * @param account The address to get votes balance\\n * @return The number of current votes for `account`\\n */\\n function getCurrentVotes(address account) external view returns (uint96) {\\n uint32 nCheckpoints = numCheckpoints[account];\\n return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\\n }\\n\\n /**\\n * @notice Determine the prior number of votes for an account as of a block number\\n * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\\n * @param account The address of the account to check\\n * @param blockNumber The block number to get the vote balance at\\n * @return The number of votes the account had as of the given block\\n */\\n function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {\\n require(blockNumber < block.number, \\\"INV::getPriorVotes: not yet determined\\\");\\n\\n uint32 nCheckpoints = numCheckpoints[account];\\n if (nCheckpoints == 0) {\\n return 0;\\n }\\n\\n // First check most recent balance\\n if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\\n return checkpoints[account][nCheckpoints - 1].votes;\\n }\\n\\n // Next check implicit zero balance\\n if (checkpoints[account][0].fromBlock > blockNumber) {\\n return 0;\\n }\\n\\n uint32 lower = 0;\\n uint32 upper = nCheckpoints - 1;\\n while (upper > lower) {\\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\\n Checkpoint memory cp = checkpoints[account][center];\\n if (cp.fromBlock == blockNumber) {\\n return cp.votes;\\n } else if (cp.fromBlock < blockNumber) {\\n lower = center;\\n } else {\\n upper = center - 1;\\n }\\n }\\n return checkpoints[account][lower].votes;\\n }\\n\\n function _delegate(address delegator, address delegatee) internal {\\n address currentDelegate = delegates[delegator];\\n uint96 delegatorBalance = uint96(accountTokens[delegator]); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n delegates[delegator] = delegatee;\\n\\n emit DelegateChanged(delegator, currentDelegate, delegatee);\\n\\n _moveDelegates(currentDelegate, delegatee, delegatorBalance);\\n }\\n\\n function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {\\n if (srcRep != dstRep && amount > 0) {\\n if (srcRep != address(0)) {\\n uint32 srcRepNum = numCheckpoints[srcRep];\\n uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\\n uint96 srcRepNew = sub96(srcRepOld, amount, \\\"INV::_moveVotes: vote amount underflows\\\");\\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\\n }\\n\\n if (dstRep != address(0)) {\\n uint32 dstRepNum = numCheckpoints[dstRep];\\n uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\\n uint96 dstRepNew = add96(dstRepOld, amount, \\\"INV::_moveVotes: vote amount overflows\\\");\\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\\n }\\n }\\n }\\n\\n function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {\\n uint32 blockNumber = safe32(block.number, \\\"INV::_writeCheckpoint: block number exceeds 32 bits\\\");\\n\\n if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\\n } else {\\n checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\\n numCheckpoints[delegatee] = nCheckpoints + 1;\\n }\\n\\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\\n }\\n\\n function getChainId() internal pure returns (uint) {\\n uint256 chainId;\\n assembly { chainId := chainid() }\\n return chainId;\\n }\\n\\n function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\\n uint96 c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n}\\n\\ncontract TimelockEscrow {\\n using SafeMath for uint;\\n\\n address public underlying;\\n address public governance;\\n address public market;\\n uint public duration = 14 days;\\n mapping (address => EscrowData) public pendingWithdrawals;\\n\\n struct EscrowData {\\n uint withdrawalTimestamp;\\n uint amount;\\n }\\n\\n constructor(address underlying_, address governance_) public {\\n underlying = underlying_;\\n governance = governance_;\\n market = msg.sender;\\n }\\n\\n // set to 0 to send funds directly to users\\n function _setEscrowDuration(uint duration_) public {\\n require(msg.sender == governance, \\\"only governance can set escrow duration\\\");\\n duration = duration_;\\n }\\n\\n function _setGov(address governance_) public {\\n require(msg.sender == governance, \\\"only governance can set its new address\\\");\\n governance = governance_;\\n }\\n\\n /**\\n * @notice assumes funds were already sent to this contract by the market. Resets escrow timelock on each withdrawal\\n */\\n function escrow(address user, uint amount) public {\\n require(msg.sender == market, \\\"only market can escrow\\\");\\n if(duration > 0) {\\n EscrowData memory withdrawal = pendingWithdrawals[user];\\n pendingWithdrawals[user] = EscrowData({\\n // we set the future withdrawal timestamp based on current `duration` to avoid applying future `duration` changes to existing withdrawals in the event of a governance attack\\n withdrawalTimestamp: block.timestamp + duration,\\n amount: withdrawal.amount.add(amount)\\n });\\n emit Escrow(user, block.timestamp + duration, amount);\\n } else { // if duration is 0, we send the funds directly to the user\\n EIP20Interface token = EIP20Interface(underlying);\\n token.transfer(user, amount);\\n }\\n }\\n\\n /**\\n * @notice returns user withdrawable amount\\n */\\n function withdrawable(address user) public view returns (uint amount) {\\n EscrowData memory withdrawal = pendingWithdrawals[user];\\n if(withdrawal.withdrawalTimestamp <= block.timestamp) {\\n amount = withdrawal.amount;\\n }\\n }\\n\\n function withdraw() public {\\n uint amount = withdrawable(msg.sender);\\n require(amount > 0, \\\"Nothing to withdraw\\\");\\n EIP20Interface token = EIP20Interface(underlying);\\n delete pendingWithdrawals[msg.sender];\\n token.transfer(msg.sender, amount);\\n emit Withdraw(msg.sender, amount);\\n }\\n\\n event Escrow(address to, uint withdrawalTimestamp, uint amount);\\n event Withdraw(address to, uint amount);\\n}\\n\\n/**\\n * @title xINV contract\\n * @notice wraps INV token\\n * @author Inverse Finance\\n */\\ncontract XINV is xInvCore {\\n\\n address public underlying;\\n TimelockEscrow public escrow;\\n\\n /**\\n * @notice Construct the xINV market\\n * @param underlying_ The address of the underlying asset\\n * @param comptroller_ The address of the Comptroller\\n * @param name_ ERC-20 name of this token\\n * @param symbol_ ERC-20 symbol of this token\\n * @param decimals_ ERC-20 decimal precision of this token\\n * @param admin_ Address of the administrator of this token\\n */\\n constructor(address underlying_,\\n ComptrollerInterface comptroller_,\\n uint rewardPerBlock_, \\n address rewardTreasury_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_,\\n address payable admin_) public {\\n // Creator of the contract is admin during initialization\\n admin = msg.sender;\\n\\n // CToken initialize does the bulk of the work\\n super.initialize(comptroller_, 1e18, rewardPerBlock_, rewardTreasury_, name_, symbol_, decimals_);\\n\\n // Set underlying and sanity check it\\n underlying = underlying_;\\n EIP20Interface(underlying).totalSupply();\\n\\n // Set the proper admin now that initialization is done\\n admin = admin_;\\n\\n // Create escrow contract\\n escrow = new TimelockEscrow(underlying_, admin_);\\n }\\n\\n /*** User Interface ***/\\n\\n /**\\n * @notice Sender supplies assets into the market and receives cTokens in exchange\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function mint(uint mintAmount) external returns (uint) {\\n (uint err,) = mintInternal(mintAmount);\\n \\n /* if user has no delegate, we inherit delegate from INV */\\n if(delegates[msg.sender] == address(0)) {\\n address invDelegate = IINV(underlying).delegates(msg.sender);\\n if(invDelegate != address(0)) {\\n _delegate(msg.sender, invDelegate);\\n }\\n }\\n return err;\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for the underlying asset\\n * @param redeemTokens The number of cTokens to redeem into underlying\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeem(uint redeemTokens) external returns (uint) {\\n return redeemInternal(redeemTokens, true);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\\n * @param redeemAmount The amount of underlying to redeem\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\\n return redeemUnderlyingInternal(redeemAmount, true);\\n }\\n\\n /*** Safe Token ***/\\n\\n /**\\n * @notice Gets balance of this contract in terms of the underlying\\n * @dev This excludes the value of the current message, if any\\n * @return The quantity of underlying tokens owned by this contract\\n */\\n function getCashPrior() internal view returns (uint) {\\n EIP20Interface token = EIP20Interface(underlying);\\n return token.balanceOf(address(this));\\n }\\n\\n /**\\n * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.\\n * This will revert due to insufficient balance or insufficient allowance.\\n * This function returns the actual amount received,\\n * which may be less than `amount` if there is a fee attached to the transfer.\\n *\\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\n function doTransferIn(address from, uint amount) internal returns (uint) {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 { // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 { // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default { // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"TOKEN_TRANSFER_IN_FAILED\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));\\n require(balanceAfter >= balanceBefore, \\\"TOKEN_TRANSFER_IN_OVERFLOW\\\");\\n return balanceAfter - balanceBefore; // underflow already checked above, just subtract\\n }\\n\\n /**\\n * @dev returns true if `from` has sufficient allowance and balance to to send `amount` to this address\\n */\\n function canTransferIn(address from, uint amount) internal view returns (bool) {\\n EIP20Interface token = EIP20Interface(underlying);\\n uint balance = token.balanceOf(from);\\n uint allowance = token.allowance(from, address(this));\\n return balance >= amount && allowance >= amount;\\n }\\n\\n /**\\n * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory\\n * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to\\n * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified\\n * it is >= amount, this should not revert in normal conditions.\\n *\\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n if(useEscrow) {\\n token.transfer(address(escrow), amount);\\n } else {\\n token.transfer(to, amount);\\n }\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 { // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 { // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default { // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"TOKEN_TRANSFER_OUT_FAILED\\\");\\n if(useEscrow) {\\n escrow.escrow(to, amount);\\n }\\n }\\n\\n function _setTimelockEscrow(TimelockEscrow newTimelockEscrow) public returns (uint) {\\n require(newTimelockEscrow.market() == address(this), \\\"sanity check: newTimelockEscrow must use this market\\\");\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n \\n TimelockEscrow oldTimelockEscrow = escrow;\\n escrow = newTimelockEscrow;\\n\\n emit NewTimelockEscrow(oldTimelockEscrow, newTimelockEscrow);\\n }\\n\\n event NewTimelockEscrow(TimelockEscrow oldTimelockEscrow, TimelockEscrow newTimelockEscrow);\\n}\",\"keccak256\":\"0x4dda0be1f259a9f81aa25f1abc073ce3ed3ab23ef8314eafb7ad72b9980caeea\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b5060405162004bb638038062004bb683398181016040526101008110156200003857600080fd5b81516020830151604080850151606086015160808701805193519597949692959194919392820192846401000000008211156200007457600080fd5b9083019060208201858111156200008a57600080fd5b8251640100000000811182820188101715620000a557600080fd5b82525081516020918201929091019080838360005b83811015620000d4578181015183820152602001620000ba565b50505050905090810190601f168015620001025780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200012657600080fd5b9083019060208201858111156200013c57600080fd5b82516401000000008111828201881017156200015757600080fd5b82525081516020918201929091019080838360005b83811015620001865781810151838201526020016200016c565b50505050905090810190601f168015620001b45780820380516001836020036101000a031916815260200191505b506040908152602082810151929091015160038054610100600160a81b03191633610100021790559193509091506200020c908890670de0b6b3a764000090899089908990899089906200032d811b6200367b17901c565b601080546001600160a01b0319166001600160a01b038a81169190911791829055604080516318160ddd60e01b8152905192909116916318160ddd91600480820192602092909190829003018186803b1580156200026957600080fd5b505afa1580156200027e573d6000803e3d6000fd5b505050506040513d60208110156200029557600080fd5b505060038054610100600160a81b0319166101006001600160a01b0384160217905560405188908290620002c990620006cc565b6001600160a01b03928316815291166020820152604080519182900301906000f080158015620002fd573d6000803e3d6000fd5b50601180546001600160a01b0319166001600160a01b0392909216919091179055506200077c9650505050505050565b60035461010090046001600160a01b031633146200037d5760405162461bcd60e51b815260040180806020018281038252602481526020018062004b3f6024913960400191505060405180910390fd5b60075415620003be5760405162461bcd60e51b815260040180806020018281038252602381526020018062004b636023913960400191505060405180910390fd5b600686905585620004015760405162461bcd60e51b815260040180806020018281038252603081526020018062004b866030913960400191505060405180910390fd5b600062000417886001600160e01b03620004f016565b905080156200046d576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b835162000482906001906020870190620006da565b50825162000498906002906020860190620006da565b506003805460ff191660ff8416179055620004b262000657565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b60035460009061010090046001600160a01b031633146200052a57620005226001603f6001600160e01b036200065c16565b905062000652565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b1580156200057057600080fd5b505afa15801562000585573d6000803e3d6000fd5b505050506040513d60208110156200059c57600080fd5b5051620005f0576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160009150505b919050565b435b90565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360108111156200068c57fe5b8360508111156200069957fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115620006c557fe5b9392505050565b6107a8806200439783390190565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200071d57805160ff19168380011785556200074d565b828001600101855582156200074d579182015b828111156200074d57825182559160200191906001019062000730565b506200075b9291506200075f565b5090565b6200065991905b808211156200075b576000815560010162000766565b613c0b806200078c6000396000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c8063852a12e31161013b578063c37f68e2116100b8578063e7a324dc1161007c578063e7a324dc146106c8578063e9c714f2146106d0578063f1127ed8146106d8578063f851a44014610732578063fe9c44ae1461073a57610248565b8063c37f68e214610608578063c3cda52014610654578063c7c934a11461069b578063db006a75146106a3578063e2fdcc17146106c057610248565b8063a6afed95116100ff578063a6afed9514610576578063b2a02ff11461057e578063b4b5ea57146105b4578063b71d1a0c146105da578063bd6d894d1461060057610248565b8063852a12e31461050f5780638aa1c05f1461052c5780638ae39cac1461054957806395d89b4114610551578063a0712d681461055957610248565b80634576b5db116101c95780636f307dc31161018d5780636f307dc3146104345780636fcfff451461043c57806370a082311461047b578063782d6fe1146104a15780637ecebe00146104e957610248565b80634576b5db146103b0578063587cde1e146103d65780635c19a95c146103fc5780635fe3b567146104245780636c540baf1461042c57610248565b806320606b701161021057806320606b70146103385780632678224714610340578063313ce567146103645780633af9e669146103825780633b1d21a2146103a857610248565b806306fdde031461024d5780630c19dc3a146102ca57806317c50d061461030257806318160ddd14610328578063182df0f514610330575b600080fd5b610255610756565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561028f578181015183820152602001610277565b50505050905090810190601f1680156102bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102f0600480360360208110156102e057600080fd5b50356001600160a01b03166107e3565b60408051918252519081900360200190f35b6102f06004803603602081101561031857600080fd5b50356001600160a01b0316610929565b6102f06109b4565b6102f06109ba565b6102f0610a1d565b610348610a38565b604080516001600160a01b039092168252519081900360200190f35b61036c610a47565b6040805160ff9092168252519081900360200190f35b6102f06004803603602081101561039857600080fd5b50356001600160a01b0316610a50565b6102f0610b06565b6102f0600480360360208110156103c657600080fd5b50356001600160a01b0316610b15565b610348600480360360208110156103ec57600080fd5b50356001600160a01b0316610c63565b6104226004803603602081101561041257600080fd5b50356001600160a01b0316610c7e565b005b610348610c8b565b6102f0610c9a565b610348610ca0565b6104626004803603602081101561045257600080fd5b50356001600160a01b0316610caf565b6040805163ffffffff9092168252519081900360200190f35b6102f06004803603602081101561049157600080fd5b50356001600160a01b0316610cc7565b6104cd600480360360408110156104b757600080fd5b506001600160a01b038135169060200135610ce2565b604080516001600160601b039092168252519081900360200190f35b6102f0600480360360208110156104ff57600080fd5b50356001600160a01b0316610f10565b6102f06004803603602081101561052557600080fd5b5035610f22565b6102f06004803603602081101561054257600080fd5b5035610f2f565b6102f0610f9e565b610255610fa4565b6102f06004803603602081101561056f57600080fd5b5035610ffc565b6102f06110c2565b6102f06004803603606081101561059457600080fd5b506001600160a01b03813581169160208101359091169060400135611232565b6104cd600480360360208110156105ca57600080fd5b50356001600160a01b03166112a3565b6102f0600480360360208110156105f057600080fd5b50356001600160a01b0316611315565b6102f06113a1565b61062e6004803603602081101561061e57600080fd5b50356001600160a01b031661145d565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610422600480360360c081101561066a57600080fd5b506001600160a01b038135169060208101359060408101359060ff6060820135169060808101359060a001356114ca565b61034861179b565b6102f0600480360360208110156106b957600080fd5b50356117aa565b6103486117b7565b6102f06117c6565b6102f06117e1565b61070a600480360360408110156106ee57600080fd5b5080356001600160a01b0316906020013563ffffffff166118e4565b6040805163ffffffff90931683526001600160601b0390911660208301528051918290030190f35b610348611919565b61074261192d565b604080519115158252519081900360200190f35b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156107db5780601f106107b0576101008083540402835291602001916107db565b820191906000526020600020905b8154815290600101906020018083116107be57829003601f168201915b505050505081565b6000306001600160a01b0316826001600160a01b03166380f556056040518163ffffffff1660e01b815260040160206040518083038186803b15801561082857600080fd5b505afa15801561083c573d6000803e3d6000fd5b505050506040513d602081101561085257600080fd5b50516001600160a01b0316146108995760405162461bcd60e51b8152600401808060200182810382526034815260200180613a116034913960400191505060405180910390fd5b60035461010090046001600160a01b031633146108c3576108bc6001603f611932565b9050610924565b601180546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f8a0324ea550ac953d4515436f05889f90a816b559ca26ee450b104d4d5a248fa929181900390910190a1505b919050565b60035460009061010090046001600160a01b0316331461094f576108bc6001603f611932565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f2856afeddd63e06a55f7d242638b9ce830a95d17f6ac86997a9acd7de2761628929181900390910190a150919050565b60085481565b60008060006109c7611998565b909250905060008260038111156109da57fe5b14610a165760405162461bcd60e51b8152600401808060200182810382526035815260200180613a9d6035913960400191505060405180910390fd5b9150505b90565b6040518060436139ad82396043019050604051809103902081565b6004546001600160a01b031681565b60035460ff1681565b6000610a5a613613565b6040518060200160405280610a6d6113a1565b90526001600160a01b0384166000908152600b6020526040812054919250908190610a99908490611a0d565b90925090506000826003811115610aac57fe5b14610afe576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610b10611a61565b905090565b60035460009061010090046001600160a01b03163314610b3b576108bc6001603f611932565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610b8057600080fd5b505afa158015610b94573d6000803e3d6000fd5b505050506040513d6020811015610baa57600080fd5b5051610bfd576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600c602052600090815260409020546001600160a01b031681565b610c883382611ae1565b50565b6005546001600160a01b031681565b60075481565b6010546001600160a01b031681565b600e6020526000908152604090205463ffffffff1681565b6001600160a01b03166000908152600b602052604090205490565b6000438210610d225760405162461bcd60e51b81526004018080602001828103825260268152602001806139066026913960400191505060405180910390fd5b6001600160a01b0383166000908152600e602052604090205463ffffffff1680610d50576000915050610f0a565b6001600160a01b0384166000908152600d6020908152604080832063ffffffff600019860181168552925290912054168310610dcc576001600160a01b0384166000908152600d602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050610f0a565b6001600160a01b0384166000908152600d6020908152604080832083805290915290205463ffffffff16831015610e07576000915050610f0a565b600060001982015b8163ffffffff168163ffffffff161115610eca57600282820363ffffffff16048103610e39613626565b506001600160a01b0387166000908152600d6020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b03169181019190915290871415610ea557602001519450610f0a9350505050565b805163ffffffff16871115610ebc57819350610ec3565b6001820392505b5050610e0f565b506001600160a01b0385166000908152600d6020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b600f6020526000908152604090205481565b6000610f0a826001611b61565b60035460009061010090046001600160a01b03163314610f55576108bc6001603f611932565b6009805490839055604080518281526020810185905281517f3b7a406bf2b66d0f83f6b1cf4c39edf1269cad80712b94cd80a44d13f61f1357929181900390910190a150919050565b60095481565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156107db5780601f106107b0576101008083540402835291602001916107db565b60008061100883611c02565b50336000908152600c60205260409020549091506001600160a01b0316610f0a5760105460408051632c3e6f0f60e11b815233600482015290516000926001600160a01b03169163587cde1e916024808301926020929190829003018186803b15801561107457600080fd5b505afa158015611088573d6000803e3d6000fd5b505050506040513d602081101561109e57600080fd5b505190506001600160a01b038116156110bb576110bb3382611ae1565b5092915050565b6000806110cd611caa565b600754909150808214156110e657600092505050610a1a565b6000806110f38484611cae565b9092509050600082600381111561110657fe5b14611158576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b600061116660095483611cd1565b9093509050600083600381111561117957fe5b146111cb576040805162461bcd60e51b815260206004820152601a60248201527f636f756c64206e6f742063616c63756c61746520726577617264000000000000604482015290519081900360640190fd5b60006008541180156111e75750600a546001600160a01b031615155b80156112045750600a54611204906001600160a01b031682611d10565b1561122157600a5461121f906001600160a01b031682611e2f565b505b600785905560009550505050505090565b6000805460ff16611277576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561128d33858585612079565b90506000805460ff191660011790559392505050565b6001600160a01b0381166000908152600e602052604081205463ffffffff16806112ce576000610c5c565b6001600160a01b0383166000908152600d6020908152604080832063ffffffff60001986011684529091529020546001600160601b03600160201b90910416915050919050565b60035460009061010090046001600160a01b0316331461133b576108bc60016045611932565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610c5c565b6000805460ff166113e6576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556113f86110c2565b14611443576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b61144b6109ba565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600b60205260408120548190819081908180611486611998565b92509050600081600381111561149857fe5b146114b45760099650600095508594508493506114c392505050565b60009650919450600093509150505b9193509193565b600060405180806139ad6043913960430190506040518091039020600160405180828054600181600116156101000203166002900480156115425780601f10611520576101008083540402835291820191611542565b820191906000526020600020905b81548152906001019060200180831161152e575b50509150506040518091039020611557612310565b3060405160200180858152602001848152602001838152602001826001600160a01b03166001600160a01b0316815260200194505050505060405160208183030381529060405280519060200120905060006040518080613afa603a91396040805191829003603a0182206020808401919091526001600160a01b038c1683830152606083018b905260808084018b90528251808503909101815260a08401835280519082012061190160f01b60c085015260c2840187905260e2808501829052835180860390910181526101028501808552815191840191909120600091829052610122860180865281905260ff8c1661014287015261016286018b905261018286018a9052935191965092945091926001926101a28083019392601f198301929081900390910190855afa158015611695573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116e75760405162461bcd60e51b8152600401808060200182810382526025815260200180613a786025913960400191505060405180910390fd5b6001600160a01b0381166000908152600f6020526040902080546001810190915589146117455760405162461bcd60e51b81526004018080602001828103825260218152602001806139f06021913960400191505060405180910390fd5b874211156117845760405162461bcd60e51b8152600401808060200182810382526025815260200180613b686025913960400191505060405180910390fd5b61178e818b611ae1565b505050505b505050505050565b600a546001600160a01b031681565b6000610f0a826001612314565b6011546001600160a01b031681565b60405180603a613afa8239603a019050604051809103902081565b6004546000906001600160a01b0316331415806117fc575033155b156118145761180d60016000611932565b9050610a1a565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600d60209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b60035461010090046001600160a01b031681565b600181565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561196157fe5b83605081111561196d57fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610c5c57fe5b6008546000908190806119b357505060065460009150611a09565b60006119bd611a61565b90506119c7613613565b60006119d3838561238f565b9250905060008160038111156119e557fe5b146119f957945060009350611a0992505050565b5051600094509250611a09915050565b9091565b6000806000611a1a613613565b611a24868661243f565b90925090506000826003811115611a3757fe5b14611a485750915060009050611a5a565b6000611a53826124a7565b9350935050505b9250929050565b601054604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b158015611aaf57600080fd5b505afa158015611ac3573d6000803e3d6000fd5b505050506040513d6020811015611ad957600080fd5b505191505090565b6001600160a01b038083166000818152600c602081815260408084208054600b845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611b5b8284836124b6565b50505050565b6000805460ff16611ba6576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611bb86110c2565b90508015611bde57611bd6816010811115611bcf57fe5b6027611932565b915050611bef565b611beb336000868661264d565b9150505b6000805460ff1916600117905592915050565b60008054819060ff16611c49576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611c5b6110c2565b90508015611c8657611c79816010811115611c7257fe5b601e611932565b925060009150611c969050565b611c903385612b14565b92509250505b6000805460ff191660011790559092909150565b4390565b600080838311611cc5575060009050818303611a5a565b50600390506000611a5a565b60008083611ce457506000905080611a5a565b83830283858281611cf157fe5b0414611d0557506002915060009050611a5a565b600092509050611a5a565b601054604080516370a0823160e01b81526001600160a01b03858116600483015291516000939290921691839183916370a0823191602480820192602092909190829003018186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d6020811015611d8f57600080fd5b505160408051636eb1769f60e11b81526001600160a01b03888116600483015230602483015291519293506000929185169163dd62ed3e91604480820192602092909190829003018186803b158015611de757600080fd5b505afa158015611dfb573d6000803e3d6000fd5b505050506040513d6020811015611e1157600080fd5b50519050848210801590611e255750848110155b9695505050505050565b601054604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b158015611e7e57600080fd5b505afa158015611e92573d6000803e3d6000fd5b505050506040513d6020811015611ea857600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b158015611f0557600080fd5b505af1158015611f19573d6000803e3d6000fd5b5050505060003d60008114611f355760208114611f3f57600080fd5b6000199150611f4b565b60206000803e60005191505b5080611f9e576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b601054604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b505190508281101561206c576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d6000fd5b505050506040513d602081101561211057600080fd5b50519050801561212f576121276003601b83612fbf565b915050610afe565b846001600160a01b0316846001600160a01b03161415612155576121276006601c611932565b6001600160a01b0384166000908152600b60205260408120548190819061217c9087611cae565b9093509150600083600381111561218f57fe5b146121b7576121ac6009601a8560038111156121a757fe5b612fbf565b945050505050610afe565b6001600160a01b0388166000908152600b60205260409020546121da9087613025565b909350905060008360038111156121ed57fe5b14612205576121ac600960198560038111156121a757fe5b6001600160a01b038088166000818152600b60209081526040808320879055938c168083529184902085905583518a8152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a36122708789886124b6565b60055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b1580156122db57600080fd5b505af11580156122ef573d6000803e3d6000fd5b50505050612300888760008061264d565b5060009998505050505050505050565b4690565b6000805460ff16612359576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561236b6110c2565b9050801561238257611bd6816010811115611bcf57fe5b611beb338560008661264d565b6000612399613613565b6000806123ae86670de0b6b3a7640000611cd1565b909250905060008260038111156123c157fe5b146123e057506040805160208101909152600081529092509050611a5a565b6000806123ed838861304b565b9092509050600082600381111561240057fe5b1461242257506040805160208101909152600081529094509250611a5a915050565b604080516020810190915290815260009890975095505050505050565b6000612449613613565b60008061245a866000015186611cd1565b9092509050600082600381111561246d57fe5b1461248c57506040805160208101909152600081529092509050611a5a565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b816001600160a01b0316836001600160a01b0316141580156124e157506000816001600160601b0316115b15612648576001600160a01b03831615612599576001600160a01b0383166000908152600e602052604081205463ffffffff169081612521576000612560565b6001600160a01b0385166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006125878285604051806060016040528060278152602001613bb060279139613076565b905061259586848484613120565b5050505b6001600160a01b03821615612648576001600160a01b0382166000908152600e602052604081205463ffffffff1690816125d4576000612613565b6001600160a01b0384166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061263a828560405180606001604052806026815260200161392c602691396132df565b905061179385848484613120565b505050565b600083158061265a575082155b6126955760405162461bcd60e51b8152600401808060200182810382526034815260200180613b346034913960400191505060405180910390fd5b61269d61363d565b6126a5611998565b60408301819052602083018260038111156126bc57fe5b60038111156126c757fe5b90525060009050816020015160038111156126de57fe5b146126fa576121276009602b836020015160038111156121a757fe5b841561277b5760608101859052604080516020810182529082015181526127219086611a0d565b608083018190526020830182600381111561273857fe5b600381111561274357fe5b905250600090508160200151600381111561275a57fe5b146127765761212760096029836020015160038111156121a757fe5b6127f4565b6127978460405180602001604052808460400151815250613349565b60608301819052602083018260038111156127ae57fe5b60038111156127b957fe5b90525060009050816020015160038111156127d057fe5b146127ec576121276009602a836020015160038111156121a757fe5b608081018490525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b038a8116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561285957600080fd5b505af115801561286d573d6000803e3d6000fd5b505050506040513d602081101561288357600080fd5b5051905080156128a35761289a6003602883612fbf565b92505050610afe565b6128b36008548360600151611cae565b60a08401819052602084018260038111156128ca57fe5b60038111156128d557fe5b90525060009050826020015160038111156128ec57fe5b146129085761289a6009602e846020015160038111156121a757fe5b6001600160a01b0387166000908152600b602052604090205460608301516129309190611cae565b60c084018190526020840182600381111561294757fe5b600381111561295257fe5b905250600090508260200151600381111561296957fe5b146129855761289a6009602d846020015160038111156121a757fe5b8160800151612992611a61565b10156129a45761289a600e602f611932565b6129b387836080015186613360565b60a082015160085560c08201516001600160a01b0388166000818152600b60209081526040918290209390935560608501518151908152905130937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef928290030190a36080820151606080840151604080516001600160a01b038c168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a1612a7b87600084606001516124b6565b60055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038c81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b158015612ae857600080fd5b505af1158015612afc573d6000803e3d6000fd5b5060009250612b09915050565b979650505050505050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b158015612b7557600080fd5b505af1158015612b89573d6000803e3d6000fd5b505050506040513d6020811015612b9f57600080fd5b505190508015612bc357612bb66003601f83612fbf565b925060009150611a5a9050565b612bcb61363d565b612bd3611998565b6040830181905260208301826003811115612bea57fe5b6003811115612bf557fe5b9052506000905081602001516003811115612c0c57fe5b14612c3657612c2860096021836020015160038111156121a757fe5b935060009250611a5a915050565b612c408686611e2f565b60c0820181905260408051602081018252908301518152612c619190613349565b6060830181905260208301826003811115612c7857fe5b6003811115612c8357fe5b9052506000905081602001516003811115612c9a57fe5b14612cec576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b612cfc6008548260600151613025565b6080830181905260208301826003811115612d1357fe5b6003811115612d1e57fe5b9052506000905081602001516003811115612d3557fe5b14612d715760405162461bcd60e51b8152600401808060200182810382526028815260200180613ad26028913960400191505060405180910390fd5b600160601b816080015110612db75760405162461bcd60e51b8152600401808060200182810382526023815260200180613b8d6023913960400191505060405180910390fd5b6001600160a01b0386166000908152600b60205260409020546060820151612ddf9190613025565b60a0830181905260208301826003811115612df657fe5b6003811115612e0157fe5b9052506000905081602001516003811115612e1857fe5b14612e545760405162461bcd60e51b815260040180806020018281038252602b815260200180613982602b913960400191505060405180910390fd5b608081015160085560a08101516001600160a01b0387166000818152600b60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b0388169130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a3612f1f60008783606001516124b6565b60055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015612f8c57600080fd5b505af1158015612fa0573d6000803e3d6000fd5b5060009250612fad915050565b8160c001519350935050509250929050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846010811115612fee57fe5b846050811115612ffa57fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610afe57fe5b60008083830184811061303d57600092509050611a5a565b506002915060009050611a5a565b6000808261305f5750600190506000611a5a565b600083858161306a57fe5b04915091509250929050565b6000836001600160601b0316836001600160601b0316111582906131185760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156130dd5781810151838201526020016130c5565b50505050905090810190601f16801561310a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061314443604051806060016040528060338152602001613a4560339139613557565b905060008463ffffffff1611801561318d57506001600160a01b0385166000908152600d6020908152604080832063ffffffff6000198901811685529252909120548282169116145b156131ec576001600160a01b0385166000908152600d60209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b0385160217905561328b565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152600d83528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252600e90935292909220805460018801909316929091169190911790555b604080516001600160601b0380861682528416602082015281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000838301826001600160601b0380871690831610156133405760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130dd5781810151838201526020016130c5565b50949350505050565b6000806000613356613613565b611a2486866135b4565b6010546001600160a01b031681156133e4576011546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519183169163a9059cbb9160448082019260009290919082900301818387803b1580156133c757600080fd5b505af11580156133db573d6000803e3d6000fd5b5050505061345d565b806001600160a01b031663a9059cbb85856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561344457600080fd5b505af1158015613458573d6000803e3d6000fd5b505050505b60003d8015613473576020811461347d57600080fd5b6000199150613489565b60206000803e60005191505b50806134dc576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b8215613550576011546040805163177ead8360e11b81526001600160a01b0388811660048301526024820188905291519190921691632efd5b0691604480830192600092919082900301818387803b15801561353757600080fd5b505af115801561354b573d6000803e3d6000fd5b505050505b5050505050565b600081600160201b84106135ac5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130dd5781810151838201526020016130c5565b509192915050565b60006135be613613565b6000806135d3670de0b6b3a764000087611cd1565b909250905060008260038111156135e657fe5b1461360557506040805160208101909152600081529092509050611a5a565b611a5381866000015161238f565b6040518060200160405280600081525090565b604080518082019091526000808252602082015290565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60035461010090046001600160a01b031633146136c95760405162461bcd60e51b81526004018080602001828103825260248152602001806138bf6024913960400191505060405180910390fd5b600754156137085760405162461bcd60e51b81526004018080602001828103825260238152602001806138e36023913960400191505060405180910390fd5b6006869055856137495760405162461bcd60e51b81526004018080602001828103825260308152602001806139526030913960400191505060405180910390fd5b600061375488610b15565b905080156137a9576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b83516137bc906001906020870190613826565b5082516137d0906002906020860190613826565b506003805460ff191660ff84161790556137e8611caa565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061386757805160ff1916838001178555613894565b82800160010185558215613894579182015b82811115613894578251825591602001919060010190613879565b506138a09291506138a4565b5090565b610a1a91905b808211156138a057600081556001016138aa56fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365494e563a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e6564494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f7773696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c4544454950373132446f6d61696e28737472696e67206e616d652c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429494e563a3a64656c656761746542795369673a20696e76616c6964206e6f6e636573616e69747920636865636b3a206e657754696d656c6f636b457363726f77206d757374207573652074686973206d61726b6574494e563a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d62657220657863656564732033322062697473494e563a3a64656c656761746542795369673a20696e76616c6964207369676e617475726565786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c454444656c65676174696f6e28616464726573732064656c6567617465652c75696e74323536206e6f6e63652c75696e7432353620657870697279296f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f494e563a3a64656c656761746542795369673a207369676e617475726520657870697265644d494e545f4e45575f544f54414c5f535550504c595f4f5645525f4341504143495459494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773a265627a7a72315820db72ac88970eca2d3b7d250ccdb12dac4c77aa6419550a12d12b9da4ffeefb1b64736f6c6343000510003260806040526212750060035534801561001757600080fd5b506040516107a83803806107a88339818101604052604081101561003a57600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b0319918216179091556001805493909216928116929092179055600280549091163317905561071b8061008d6000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80636f307dc3116100665780636f307dc31461013457806380f556051461013c578063ce513b6f14610144578063d215f3181461016a578063f3f43703146101905761009e565b80630fb5a6b4146100a35780631c411df3146100bd5780632efd5b06146100dc5780633ccfd60b146101085780635aa6e67514610110575b600080fd5b6100ab6101cf565b60408051918252519081900360200190f35b6100da600480360360208110156100d357600080fd5b50356101d5565b005b6100da600480360360408110156100f257600080fd5b506001600160a01b038135169060200135610223565b6100da6103e8565b610118610517565b604080516001600160a01b039092168252519081900360200190f35b610118610526565b610118610535565b6100ab6004803603602081101561015a57600080fd5b50356001600160a01b0316610544565b6100da6004803603602081101561018057600080fd5b50356001600160a01b0316610599565b6101b6600480360360208110156101a657600080fd5b50356001600160a01b0316610604565b6040805192835260208301919091528051918290030190f35b60035481565b6001546001600160a01b0316331461021e5760405162461bcd60e51b81526004018080602001828103825260278152602001806106c06027913960400191505060405180910390fd5b600355565b6002546001600160a01b0316331461027b576040805162461bcd60e51b81526020600482015260166024820152756f6e6c79206d61726b65742063616e20657363726f7760501b604482015290519081900360640190fd5b6003541561035d5761028b61067e565b506001600160a01b0382166000908152600460209081526040918290208251808401845281548152600190910154818301908152835180850190945260035442018452519092918201906102e5908563ffffffff61061d16565b90526001600160a01b0384166000818152600460209081526040918290208451815593810151600190940193909355600354815192835242019282019290925280820184905290517fdbe3ea2036231446c1c0e4706a5d2a242036540e5708cb7972a396fad591606d9181900360600190a1506103e4565b600080546040805163a9059cbb60e01b81526001600160a01b0386811660048301526024820186905291519190921692839263a9059cbb9260448083019360209383900390910190829087803b1580156103b657600080fd5b505af11580156103ca573d6000803e3d6000fd5b505050506040513d60208110156103e057600080fd5b5050505b5050565b60006103f333610544565b905060008111610440576040805162461bcd60e51b81526020600482015260136024820152724e6f7468696e6720746f20776974686472617760681b604482015290519081900360640190fd5b6000805433808352600460208181526040808620868155600101869055805163a9059cbb60e01b8152928301939093526024820186905291516001600160a01b0390931693849363a9059cbb936044808501949193918390030190829087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d60208110156104d657600080fd5b5050604080513381526020810184905281517f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364929181900390910190a15050565b6001546001600160a01b031681565b6000546001600160a01b031681565b6002546001600160a01b031681565b600061054e61067e565b506001600160a01b0382166000908152600460209081526040918290208251808401909352805480845260019091015491830191909152421061059357806020015191505b50919050565b6001546001600160a01b031633146105e25760405162461bcd60e51b81526004018080602001828103825260278152602001806106996027913960400191505060405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6004602052600090815260409020805460019091015482565b600082820183811015610677576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60405180604001604052806000815260200160008152509056fe6f6e6c7920676f7665726e616e63652063616e2073657420697473206e657720616464726573736f6e6c7920676f7665726e616e63652063616e2073657420657363726f77206475726174696f6ea265627a7a723158201ec80ddaa1cfa806c09a521ac2f315cdf492b6820c6091c4d55a10be8ae6e40564736f6c634300051000326f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102485760003560e01c8063852a12e31161013b578063c37f68e2116100b8578063e7a324dc1161007c578063e7a324dc146106c8578063e9c714f2146106d0578063f1127ed8146106d8578063f851a44014610732578063fe9c44ae1461073a57610248565b8063c37f68e214610608578063c3cda52014610654578063c7c934a11461069b578063db006a75146106a3578063e2fdcc17146106c057610248565b8063a6afed95116100ff578063a6afed9514610576578063b2a02ff11461057e578063b4b5ea57146105b4578063b71d1a0c146105da578063bd6d894d1461060057610248565b8063852a12e31461050f5780638aa1c05f1461052c5780638ae39cac1461054957806395d89b4114610551578063a0712d681461055957610248565b80634576b5db116101c95780636f307dc31161018d5780636f307dc3146104345780636fcfff451461043c57806370a082311461047b578063782d6fe1146104a15780637ecebe00146104e957610248565b80634576b5db146103b0578063587cde1e146103d65780635c19a95c146103fc5780635fe3b567146104245780636c540baf1461042c57610248565b806320606b701161021057806320606b70146103385780632678224714610340578063313ce567146103645780633af9e669146103825780633b1d21a2146103a857610248565b806306fdde031461024d5780630c19dc3a146102ca57806317c50d061461030257806318160ddd14610328578063182df0f514610330575b600080fd5b610255610756565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561028f578181015183820152602001610277565b50505050905090810190601f1680156102bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102f0600480360360208110156102e057600080fd5b50356001600160a01b03166107e3565b60408051918252519081900360200190f35b6102f06004803603602081101561031857600080fd5b50356001600160a01b0316610929565b6102f06109b4565b6102f06109ba565b6102f0610a1d565b610348610a38565b604080516001600160a01b039092168252519081900360200190f35b61036c610a47565b6040805160ff9092168252519081900360200190f35b6102f06004803603602081101561039857600080fd5b50356001600160a01b0316610a50565b6102f0610b06565b6102f0600480360360208110156103c657600080fd5b50356001600160a01b0316610b15565b610348600480360360208110156103ec57600080fd5b50356001600160a01b0316610c63565b6104226004803603602081101561041257600080fd5b50356001600160a01b0316610c7e565b005b610348610c8b565b6102f0610c9a565b610348610ca0565b6104626004803603602081101561045257600080fd5b50356001600160a01b0316610caf565b6040805163ffffffff9092168252519081900360200190f35b6102f06004803603602081101561049157600080fd5b50356001600160a01b0316610cc7565b6104cd600480360360408110156104b757600080fd5b506001600160a01b038135169060200135610ce2565b604080516001600160601b039092168252519081900360200190f35b6102f0600480360360208110156104ff57600080fd5b50356001600160a01b0316610f10565b6102f06004803603602081101561052557600080fd5b5035610f22565b6102f06004803603602081101561054257600080fd5b5035610f2f565b6102f0610f9e565b610255610fa4565b6102f06004803603602081101561056f57600080fd5b5035610ffc565b6102f06110c2565b6102f06004803603606081101561059457600080fd5b506001600160a01b03813581169160208101359091169060400135611232565b6104cd600480360360208110156105ca57600080fd5b50356001600160a01b03166112a3565b6102f0600480360360208110156105f057600080fd5b50356001600160a01b0316611315565b6102f06113a1565b61062e6004803603602081101561061e57600080fd5b50356001600160a01b031661145d565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610422600480360360c081101561066a57600080fd5b506001600160a01b038135169060208101359060408101359060ff6060820135169060808101359060a001356114ca565b61034861179b565b6102f0600480360360208110156106b957600080fd5b50356117aa565b6103486117b7565b6102f06117c6565b6102f06117e1565b61070a600480360360408110156106ee57600080fd5b5080356001600160a01b0316906020013563ffffffff166118e4565b6040805163ffffffff90931683526001600160601b0390911660208301528051918290030190f35b610348611919565b61074261192d565b604080519115158252519081900360200190f35b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156107db5780601f106107b0576101008083540402835291602001916107db565b820191906000526020600020905b8154815290600101906020018083116107be57829003601f168201915b505050505081565b6000306001600160a01b0316826001600160a01b03166380f556056040518163ffffffff1660e01b815260040160206040518083038186803b15801561082857600080fd5b505afa15801561083c573d6000803e3d6000fd5b505050506040513d602081101561085257600080fd5b50516001600160a01b0316146108995760405162461bcd60e51b8152600401808060200182810382526034815260200180613a116034913960400191505060405180910390fd5b60035461010090046001600160a01b031633146108c3576108bc6001603f611932565b9050610924565b601180546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f8a0324ea550ac953d4515436f05889f90a816b559ca26ee450b104d4d5a248fa929181900390910190a1505b919050565b60035460009061010090046001600160a01b0316331461094f576108bc6001603f611932565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f2856afeddd63e06a55f7d242638b9ce830a95d17f6ac86997a9acd7de2761628929181900390910190a150919050565b60085481565b60008060006109c7611998565b909250905060008260038111156109da57fe5b14610a165760405162461bcd60e51b8152600401808060200182810382526035815260200180613a9d6035913960400191505060405180910390fd5b9150505b90565b6040518060436139ad82396043019050604051809103902081565b6004546001600160a01b031681565b60035460ff1681565b6000610a5a613613565b6040518060200160405280610a6d6113a1565b90526001600160a01b0384166000908152600b6020526040812054919250908190610a99908490611a0d565b90925090506000826003811115610aac57fe5b14610afe576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610b10611a61565b905090565b60035460009061010090046001600160a01b03163314610b3b576108bc6001603f611932565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610b8057600080fd5b505afa158015610b94573d6000803e3d6000fd5b505050506040513d6020811015610baa57600080fd5b5051610bfd576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600c602052600090815260409020546001600160a01b031681565b610c883382611ae1565b50565b6005546001600160a01b031681565b60075481565b6010546001600160a01b031681565b600e6020526000908152604090205463ffffffff1681565b6001600160a01b03166000908152600b602052604090205490565b6000438210610d225760405162461bcd60e51b81526004018080602001828103825260268152602001806139066026913960400191505060405180910390fd5b6001600160a01b0383166000908152600e602052604090205463ffffffff1680610d50576000915050610f0a565b6001600160a01b0384166000908152600d6020908152604080832063ffffffff600019860181168552925290912054168310610dcc576001600160a01b0384166000908152600d602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050610f0a565b6001600160a01b0384166000908152600d6020908152604080832083805290915290205463ffffffff16831015610e07576000915050610f0a565b600060001982015b8163ffffffff168163ffffffff161115610eca57600282820363ffffffff16048103610e39613626565b506001600160a01b0387166000908152600d6020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b03169181019190915290871415610ea557602001519450610f0a9350505050565b805163ffffffff16871115610ebc57819350610ec3565b6001820392505b5050610e0f565b506001600160a01b0385166000908152600d6020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b600f6020526000908152604090205481565b6000610f0a826001611b61565b60035460009061010090046001600160a01b03163314610f55576108bc6001603f611932565b6009805490839055604080518281526020810185905281517f3b7a406bf2b66d0f83f6b1cf4c39edf1269cad80712b94cd80a44d13f61f1357929181900390910190a150919050565b60095481565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156107db5780601f106107b0576101008083540402835291602001916107db565b60008061100883611c02565b50336000908152600c60205260409020549091506001600160a01b0316610f0a5760105460408051632c3e6f0f60e11b815233600482015290516000926001600160a01b03169163587cde1e916024808301926020929190829003018186803b15801561107457600080fd5b505afa158015611088573d6000803e3d6000fd5b505050506040513d602081101561109e57600080fd5b505190506001600160a01b038116156110bb576110bb3382611ae1565b5092915050565b6000806110cd611caa565b600754909150808214156110e657600092505050610a1a565b6000806110f38484611cae565b9092509050600082600381111561110657fe5b14611158576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b600061116660095483611cd1565b9093509050600083600381111561117957fe5b146111cb576040805162461bcd60e51b815260206004820152601a60248201527f636f756c64206e6f742063616c63756c61746520726577617264000000000000604482015290519081900360640190fd5b60006008541180156111e75750600a546001600160a01b031615155b80156112045750600a54611204906001600160a01b031682611d10565b1561122157600a5461121f906001600160a01b031682611e2f565b505b600785905560009550505050505090565b6000805460ff16611277576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561128d33858585612079565b90506000805460ff191660011790559392505050565b6001600160a01b0381166000908152600e602052604081205463ffffffff16806112ce576000610c5c565b6001600160a01b0383166000908152600d6020908152604080832063ffffffff60001986011684529091529020546001600160601b03600160201b90910416915050919050565b60035460009061010090046001600160a01b0316331461133b576108bc60016045611932565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610c5c565b6000805460ff166113e6576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556113f86110c2565b14611443576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b61144b6109ba565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600b60205260408120548190819081908180611486611998565b92509050600081600381111561149857fe5b146114b45760099650600095508594508493506114c392505050565b60009650919450600093509150505b9193509193565b600060405180806139ad6043913960430190506040518091039020600160405180828054600181600116156101000203166002900480156115425780601f10611520576101008083540402835291820191611542565b820191906000526020600020905b81548152906001019060200180831161152e575b50509150506040518091039020611557612310565b3060405160200180858152602001848152602001838152602001826001600160a01b03166001600160a01b0316815260200194505050505060405160208183030381529060405280519060200120905060006040518080613afa603a91396040805191829003603a0182206020808401919091526001600160a01b038c1683830152606083018b905260808084018b90528251808503909101815260a08401835280519082012061190160f01b60c085015260c2840187905260e2808501829052835180860390910181526101028501808552815191840191909120600091829052610122860180865281905260ff8c1661014287015261016286018b905261018286018a9052935191965092945091926001926101a28083019392601f198301929081900390910190855afa158015611695573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116e75760405162461bcd60e51b8152600401808060200182810382526025815260200180613a786025913960400191505060405180910390fd5b6001600160a01b0381166000908152600f6020526040902080546001810190915589146117455760405162461bcd60e51b81526004018080602001828103825260218152602001806139f06021913960400191505060405180910390fd5b874211156117845760405162461bcd60e51b8152600401808060200182810382526025815260200180613b686025913960400191505060405180910390fd5b61178e818b611ae1565b505050505b505050505050565b600a546001600160a01b031681565b6000610f0a826001612314565b6011546001600160a01b031681565b60405180603a613afa8239603a019050604051809103902081565b6004546000906001600160a01b0316331415806117fc575033155b156118145761180d60016000611932565b9050610a1a565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600d60209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b60035461010090046001600160a01b031681565b600181565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561196157fe5b83605081111561196d57fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610c5c57fe5b6008546000908190806119b357505060065460009150611a09565b60006119bd611a61565b90506119c7613613565b60006119d3838561238f565b9250905060008160038111156119e557fe5b146119f957945060009350611a0992505050565b5051600094509250611a09915050565b9091565b6000806000611a1a613613565b611a24868661243f565b90925090506000826003811115611a3757fe5b14611a485750915060009050611a5a565b6000611a53826124a7565b9350935050505b9250929050565b601054604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b158015611aaf57600080fd5b505afa158015611ac3573d6000803e3d6000fd5b505050506040513d6020811015611ad957600080fd5b505191505090565b6001600160a01b038083166000818152600c602081815260408084208054600b845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611b5b8284836124b6565b50505050565b6000805460ff16611ba6576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611bb86110c2565b90508015611bde57611bd6816010811115611bcf57fe5b6027611932565b915050611bef565b611beb336000868661264d565b9150505b6000805460ff1916600117905592915050565b60008054819060ff16611c49576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611c5b6110c2565b90508015611c8657611c79816010811115611c7257fe5b601e611932565b925060009150611c969050565b611c903385612b14565b92509250505b6000805460ff191660011790559092909150565b4390565b600080838311611cc5575060009050818303611a5a565b50600390506000611a5a565b60008083611ce457506000905080611a5a565b83830283858281611cf157fe5b0414611d0557506002915060009050611a5a565b600092509050611a5a565b601054604080516370a0823160e01b81526001600160a01b03858116600483015291516000939290921691839183916370a0823191602480820192602092909190829003018186803b158015611d6557600080fd5b505afa158015611d79573d6000803e3d6000fd5b505050506040513d6020811015611d8f57600080fd5b505160408051636eb1769f60e11b81526001600160a01b03888116600483015230602483015291519293506000929185169163dd62ed3e91604480820192602092909190829003018186803b158015611de757600080fd5b505afa158015611dfb573d6000803e3d6000fd5b505050506040513d6020811015611e1157600080fd5b50519050848210801590611e255750848110155b9695505050505050565b601054604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b158015611e7e57600080fd5b505afa158015611e92573d6000803e3d6000fd5b505050506040513d6020811015611ea857600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b158015611f0557600080fd5b505af1158015611f19573d6000803e3d6000fd5b5050505060003d60008114611f355760208114611f3f57600080fd5b6000199150611f4b565b60206000803e60005191505b5080611f9e576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b601054604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b505190508281101561206c576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b1580156120e657600080fd5b505af11580156120fa573d6000803e3d6000fd5b505050506040513d602081101561211057600080fd5b50519050801561212f576121276003601b83612fbf565b915050610afe565b846001600160a01b0316846001600160a01b03161415612155576121276006601c611932565b6001600160a01b0384166000908152600b60205260408120548190819061217c9087611cae565b9093509150600083600381111561218f57fe5b146121b7576121ac6009601a8560038111156121a757fe5b612fbf565b945050505050610afe565b6001600160a01b0388166000908152600b60205260409020546121da9087613025565b909350905060008360038111156121ed57fe5b14612205576121ac600960198560038111156121a757fe5b6001600160a01b038088166000818152600b60209081526040808320879055938c168083529184902085905583518a8152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a36122708789886124b6565b60055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b1580156122db57600080fd5b505af11580156122ef573d6000803e3d6000fd5b50505050612300888760008061264d565b5060009998505050505050505050565b4690565b6000805460ff16612359576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561236b6110c2565b9050801561238257611bd6816010811115611bcf57fe5b611beb338560008661264d565b6000612399613613565b6000806123ae86670de0b6b3a7640000611cd1565b909250905060008260038111156123c157fe5b146123e057506040805160208101909152600081529092509050611a5a565b6000806123ed838861304b565b9092509050600082600381111561240057fe5b1461242257506040805160208101909152600081529094509250611a5a915050565b604080516020810190915290815260009890975095505050505050565b6000612449613613565b60008061245a866000015186611cd1565b9092509050600082600381111561246d57fe5b1461248c57506040805160208101909152600081529092509050611a5a565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b816001600160a01b0316836001600160a01b0316141580156124e157506000816001600160601b0316115b15612648576001600160a01b03831615612599576001600160a01b0383166000908152600e602052604081205463ffffffff169081612521576000612560565b6001600160a01b0385166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006125878285604051806060016040528060278152602001613bb060279139613076565b905061259586848484613120565b5050505b6001600160a01b03821615612648576001600160a01b0382166000908152600e602052604081205463ffffffff1690816125d4576000612613565b6001600160a01b0384166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061263a828560405180606001604052806026815260200161392c602691396132df565b905061179385848484613120565b505050565b600083158061265a575082155b6126955760405162461bcd60e51b8152600401808060200182810382526034815260200180613b346034913960400191505060405180910390fd5b61269d61363d565b6126a5611998565b60408301819052602083018260038111156126bc57fe5b60038111156126c757fe5b90525060009050816020015160038111156126de57fe5b146126fa576121276009602b836020015160038111156121a757fe5b841561277b5760608101859052604080516020810182529082015181526127219086611a0d565b608083018190526020830182600381111561273857fe5b600381111561274357fe5b905250600090508160200151600381111561275a57fe5b146127765761212760096029836020015160038111156121a757fe5b6127f4565b6127978460405180602001604052808460400151815250613349565b60608301819052602083018260038111156127ae57fe5b60038111156127b957fe5b90525060009050816020015160038111156127d057fe5b146127ec576121276009602a836020015160038111156121a757fe5b608081018490525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b038a8116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561285957600080fd5b505af115801561286d573d6000803e3d6000fd5b505050506040513d602081101561288357600080fd5b5051905080156128a35761289a6003602883612fbf565b92505050610afe565b6128b36008548360600151611cae565b60a08401819052602084018260038111156128ca57fe5b60038111156128d557fe5b90525060009050826020015160038111156128ec57fe5b146129085761289a6009602e846020015160038111156121a757fe5b6001600160a01b0387166000908152600b602052604090205460608301516129309190611cae565b60c084018190526020840182600381111561294757fe5b600381111561295257fe5b905250600090508260200151600381111561296957fe5b146129855761289a6009602d846020015160038111156121a757fe5b8160800151612992611a61565b10156129a45761289a600e602f611932565b6129b387836080015186613360565b60a082015160085560c08201516001600160a01b0388166000818152600b60209081526040918290209390935560608501518151908152905130937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef928290030190a36080820151606080840151604080516001600160a01b038c168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a1612a7b87600084606001516124b6565b60055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038c81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b158015612ae857600080fd5b505af1158015612afc573d6000803e3d6000fd5b5060009250612b09915050565b979650505050505050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b158015612b7557600080fd5b505af1158015612b89573d6000803e3d6000fd5b505050506040513d6020811015612b9f57600080fd5b505190508015612bc357612bb66003601f83612fbf565b925060009150611a5a9050565b612bcb61363d565b612bd3611998565b6040830181905260208301826003811115612bea57fe5b6003811115612bf557fe5b9052506000905081602001516003811115612c0c57fe5b14612c3657612c2860096021836020015160038111156121a757fe5b935060009250611a5a915050565b612c408686611e2f565b60c0820181905260408051602081018252908301518152612c619190613349565b6060830181905260208301826003811115612c7857fe5b6003811115612c8357fe5b9052506000905081602001516003811115612c9a57fe5b14612cec576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b612cfc6008548260600151613025565b6080830181905260208301826003811115612d1357fe5b6003811115612d1e57fe5b9052506000905081602001516003811115612d3557fe5b14612d715760405162461bcd60e51b8152600401808060200182810382526028815260200180613ad26028913960400191505060405180910390fd5b600160601b816080015110612db75760405162461bcd60e51b8152600401808060200182810382526023815260200180613b8d6023913960400191505060405180910390fd5b6001600160a01b0386166000908152600b60205260409020546060820151612ddf9190613025565b60a0830181905260208301826003811115612df657fe5b6003811115612e0157fe5b9052506000905081602001516003811115612e1857fe5b14612e545760405162461bcd60e51b815260040180806020018281038252602b815260200180613982602b913960400191505060405180910390fd5b608081015160085560a08101516001600160a01b0387166000818152600b60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b0388169130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a3612f1f60008783606001516124b6565b60055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015612f8c57600080fd5b505af1158015612fa0573d6000803e3d6000fd5b5060009250612fad915050565b8160c001519350935050509250929050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846010811115612fee57fe5b846050811115612ffa57fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610afe57fe5b60008083830184811061303d57600092509050611a5a565b506002915060009050611a5a565b6000808261305f5750600190506000611a5a565b600083858161306a57fe5b04915091509250929050565b6000836001600160601b0316836001600160601b0316111582906131185760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156130dd5781810151838201526020016130c5565b50505050905090810190601f16801561310a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061314443604051806060016040528060338152602001613a4560339139613557565b905060008463ffffffff1611801561318d57506001600160a01b0385166000908152600d6020908152604080832063ffffffff6000198901811685529252909120548282169116145b156131ec576001600160a01b0385166000908152600d60209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b0385160217905561328b565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152600d83528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252600e90935292909220805460018801909316929091169190911790555b604080516001600160601b0380861682528416602082015281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000838301826001600160601b0380871690831610156133405760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130dd5781810151838201526020016130c5565b50949350505050565b6000806000613356613613565b611a2486866135b4565b6010546001600160a01b031681156133e4576011546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519183169163a9059cbb9160448082019260009290919082900301818387803b1580156133c757600080fd5b505af11580156133db573d6000803e3d6000fd5b5050505061345d565b806001600160a01b031663a9059cbb85856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561344457600080fd5b505af1158015613458573d6000803e3d6000fd5b505050505b60003d8015613473576020811461347d57600080fd5b6000199150613489565b60206000803e60005191505b50806134dc576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b8215613550576011546040805163177ead8360e11b81526001600160a01b0388811660048301526024820188905291519190921691632efd5b0691604480830192600092919082900301818387803b15801561353757600080fd5b505af115801561354b573d6000803e3d6000fd5b505050505b5050505050565b600081600160201b84106135ac5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130dd5781810151838201526020016130c5565b509192915050565b60006135be613613565b6000806135d3670de0b6b3a764000087611cd1565b909250905060008260038111156135e657fe5b1461360557506040805160208101909152600081529092509050611a5a565b611a5381866000015161238f565b6040518060200160405280600081525090565b604080518082019091526000808252602082015290565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60035461010090046001600160a01b031633146136c95760405162461bcd60e51b81526004018080602001828103825260248152602001806138bf6024913960400191505060405180910390fd5b600754156137085760405162461bcd60e51b81526004018080602001828103825260238152602001806138e36023913960400191505060405180910390fd5b6006869055856137495760405162461bcd60e51b81526004018080602001828103825260308152602001806139526030913960400191505060405180910390fd5b600061375488610b15565b905080156137a9576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b83516137bc906001906020870190613826565b5082516137d0906002906020860190613826565b506003805460ff191660ff84161790556137e8611caa565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061386757805160ff1916838001178555613894565b82800160010185558215613894579182015b82811115613894578251825591602001919060010190613879565b506138a09291506138a4565b5090565b610a1a91905b808211156138a057600081556001016138aa56fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365494e563a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e6564494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f7773696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c4544454950373132446f6d61696e28737472696e67206e616d652c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429494e563a3a64656c656761746542795369673a20696e76616c6964206e6f6e636573616e69747920636865636b3a206e657754696d656c6f636b457363726f77206d757374207573652074686973206d61726b6574494e563a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d62657220657863656564732033322062697473494e563a3a64656c656761746542795369673a20696e76616c6964207369676e617475726565786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c454444656c65676174696f6e28616464726573732064656c6567617465652c75696e74323536206e6f6e63652c75696e7432353620657870697279296f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f494e563a3a64656c656761746542795369673a207369676e617475726520657870697265644d494e545f4e45575f544f54414c5f535550504c595f4f5645525f4341504143495459494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773a265627a7a72315820db72ac88970eca2d3b7d250ccdb12dac4c77aa6419550a12d12b9da4ffeefb1b64736f6c63430005100032", + "solcInputHash": "f91912da5fadc7dce3430f4d2e6691b6", + "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"underlying_\",\"type\":\"address\"},{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"comptroller_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"rewardPerBlock_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"rewardTreasury_\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"},{\"internalType\":\"address payable\",\"name\":\"admin_\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"fromDelegate\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"toDelegate\",\"type\":\"address\"}],\"name\":\"DelegateChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegate\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"DelegateVotesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"error\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"info\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"detail\",\"type\":\"uint256\"}],\"name\":\"Failure\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"mintAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"mintTokens\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"NewAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract ComptrollerInterface\",\"name\":\"oldComptroller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contract ComptrollerInterface\",\"name\":\"newComptroller\",\"type\":\"address\"}],\"name\":\"NewComptroller\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldPendingAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"NewPendingAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldRewardPerBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newRewardPerBlock\",\"type\":\"uint256\"}],\"name\":\"NewRewardPerBlock\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRewardTreasury\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRewardTreasury\",\"type\":\"address\"}],\"name\":\"NewRewardTreasury\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract TimelockEscrow\",\"name\":\"oldTimelockEscrow\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contract TimelockEscrow\",\"name\":\"newTimelockEscrow\",\"type\":\"address\"}],\"name\":\"NewTimelockEscrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"redeemer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"Redeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[],\"name\":\"_acceptAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"newComptroller\",\"type\":\"address\"}],\"name\":\"_setComptroller\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newPendingAdmin\",\"type\":\"address\"}],\"name\":\"_setPendingAdmin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newRewardPerBlock\",\"type\":\"uint256\"}],\"name\":\"_setRewardPerBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRewardTreasury\",\"type\":\"address\"}],\"name\":\"_setRewardTreasury\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"contract TimelockEscrow\",\"name\":\"newTimelockEscrow\",\"type\":\"address\"}],\"name\":\"_setTimelockEscrow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"accrualBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"accrueInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOfUnderlying\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"borrowIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"name\":\"checkpoints\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fromBlock\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"votes\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"comptroller\",\"outputs\":[{\"internalType\":\"contract ComptrollerInterface\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegates\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"escrow\",\"outputs\":[{\"internalType\":\"contract TimelockEscrow\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"exchangeRateCurrent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"exchangeRateStored\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getAccountSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getCash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getCurrentVotes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getPriorVotes\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isCToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mintAmount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"numCheckpoints\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pendingAdmin\",\"outputs\":[{\"internalType\":\"address payable\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"redeem\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlying\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rewardPerBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rewardTreasury\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"liquidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"seizeTokens\",\"type\":\"uint256\"}],\"name\":\"seize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"syncDelegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"underlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Inverse Finance\",\"methods\":{\"_acceptAdmin()\":{\"details\":\"Admin function for pending admin to accept role and update admin\",\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"_setComptroller(address)\":{\"details\":\"Admin function to set a new comptroller\",\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"_setPendingAdmin(address)\":{\"details\":\"Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\",\"params\":{\"newPendingAdmin\":\"New pending admin.\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"balanceOf(address)\":{\"params\":{\"owner\":\"The address of the account to query\"},\"return\":\"The number of tokens owned by `owner`\"},\"balanceOfUnderlying(address)\":{\"params\":{\"owner\":\"The address of the account to query\"},\"return\":\"The amount of underlying owned by `owner`\"},\"constructor\":{\"params\":{\"admin_\":\"Address of the administrator of this token\",\"comptroller_\":\"The address of the Comptroller\",\"decimals_\":\"ERC-20 decimal precision of this token\",\"name_\":\"ERC-20 name of this token\",\"symbol_\":\"ERC-20 symbol of this token\",\"underlying_\":\"The address of the underlying asset\"}},\"exchangeRateCurrent()\":{\"return\":\"Calculated exchange rate scaled by 1e18\"},\"exchangeRateStored()\":{\"return\":\"Calculated exchange rate scaled by 1e18\"},\"getAccountSnapshot(address)\":{\"details\":\"This is used by comptroller to more efficiently perform liquidity checks.\",\"params\":{\"account\":\"Address of the account to snapshot\"},\"return\":\"(possible error, token balance, borrow balance, exchange rate mantissa)\"},\"getCash()\":{\"return\":\"The quantity of underlying asset owned by this contract\"},\"getCurrentVotes(address)\":{\"params\":{\"account\":\"The address to get votes balance\"},\"return\":\"The number of current votes for `account`\"},\"getPriorVotes(address,uint256)\":{\"details\":\"Block number must be a finalized block or else this function will revert to prevent misinformation.\",\"params\":{\"account\":\"The address of the account to check\",\"blockNumber\":\"The block number to get the vote balance at\"},\"return\":\"The number of votes the account had as of the given block\"},\"mint(uint256)\":{\"params\":{\"mintAmount\":\"The amount of the underlying asset to supply\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"redeem(uint256)\":{\"params\":{\"redeemTokens\":\"The number of cTokens to redeem into underlying\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"redeemUnderlying(uint256)\":{\"params\":{\"redeemAmount\":\"The amount of underlying to redeem\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"seize(address,address,uint256)\":{\"details\":\"Will fail unless called by another cToken during the process of liquidation. Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\",\"params\":{\"borrower\":\"The account having collateral seized\",\"liquidator\":\"The account receiving seized collateral\",\"seizeTokens\":\"The number of cTokens to seize\"},\"return\":\"uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\"},\"syncDelegate(address)\":{\"params\":{\"user\":\"Address to sync\"}}},\"title\":\"xINV contract\"},\"userdoc\":{\"methods\":{\"_acceptAdmin()\":{\"notice\":\"Accepts transfer of admin rights. msg.sender must be pendingAdmin\"},\"_setComptroller(address)\":{\"notice\":\"Sets a new comptroller for the market\"},\"_setPendingAdmin(address)\":{\"notice\":\"Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\"},\"balanceOf(address)\":{\"notice\":\"Get the token balance of the `owner`\"},\"balanceOfUnderlying(address)\":{\"notice\":\"Get the underlying balance of the `owner`\"},\"constructor\":\"Construct the xINV market\",\"exchangeRateStored()\":{\"notice\":\"Calculates the exchange rate from the underlying to the CToken\"},\"getAccountSnapshot(address)\":{\"notice\":\"Get a snapshot of the account's balances, and the cached exchange rate\"},\"getCash()\":{\"notice\":\"Get cash balance of this cToken in the underlying asset\"},\"getCurrentVotes(address)\":{\"notice\":\"Gets the current votes balance for `account`\"},\"getPriorVotes(address,uint256)\":{\"notice\":\"Determine the prior number of votes for an account as of a block number\"},\"mint(uint256)\":{\"notice\":\"Sender supplies assets into the market and receives cTokens in exchange\"},\"redeem(uint256)\":{\"notice\":\"Sender redeems cTokens in exchange for the underlying asset\"},\"redeemUnderlying(uint256)\":{\"notice\":\"Sender redeems cTokens in exchange for a specified amount of underlying asset\"},\"seize(address,address,uint256)\":{\"notice\":\"Transfers collateral tokens (this market) to the liquidator.\"},\"syncDelegate(address)\":{\"notice\":\"Sync user delegate from INV\"}},\"notice\":\"wraps INV token\"}},\"settings\":{\"compilationTarget\":{\"contracts/XINV.sol\":\"XINV\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/CarefulMath.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title Careful Math\\n * @author Compound\\n * @notice Derived from OpenZeppelin's SafeMath library\\n * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol\\n */\\ncontract CarefulMath {\\n\\n /**\\n * @dev Possible error codes that we can return\\n */\\n enum MathError {\\n NO_ERROR,\\n DIVISION_BY_ZERO,\\n INTEGER_OVERFLOW,\\n INTEGER_UNDERFLOW\\n }\\n\\n /**\\n * @dev Multiplies two numbers, returns an error on overflow.\\n */\\n function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (a == 0) {\\n return (MathError.NO_ERROR, 0);\\n }\\n\\n uint c = a * b;\\n\\n if (c / a != b) {\\n return (MathError.INTEGER_OVERFLOW, 0);\\n } else {\\n return (MathError.NO_ERROR, c);\\n }\\n }\\n\\n /**\\n * @dev Integer division of two numbers, truncating the quotient.\\n */\\n function divUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (b == 0) {\\n return (MathError.DIVISION_BY_ZERO, 0);\\n }\\n\\n return (MathError.NO_ERROR, a / b);\\n }\\n\\n /**\\n * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).\\n */\\n function subUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n if (b <= a) {\\n return (MathError.NO_ERROR, a - b);\\n } else {\\n return (MathError.INTEGER_UNDERFLOW, 0);\\n }\\n }\\n\\n /**\\n * @dev Adds two numbers, returns an error on overflow.\\n */\\n function addUInt(uint a, uint b) internal pure returns (MathError, uint) {\\n uint c = a + b;\\n\\n if (c >= a) {\\n return (MathError.NO_ERROR, c);\\n } else {\\n return (MathError.INTEGER_OVERFLOW, 0);\\n }\\n }\\n\\n /**\\n * @dev add a and b and then subtract c\\n */\\n function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {\\n (MathError err0, uint sum) = addUInt(a, b);\\n\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, 0);\\n }\\n\\n return subUInt(sum, c);\\n }\\n}\",\"keccak256\":\"0x0647348f27e41d22555d99eebd217dee02a4d737df6accd7cce5347a7487c7de\"},\"contracts/ComptrollerInterface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ncontract ComptrollerInterface {\\n /// @notice Indicator that this is a Comptroller contract (for inspection)\\n bool public constant isComptroller = true;\\n\\n /*** Assets You Are In ***/\\n\\n function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);\\n function exitMarket(address cToken) external returns (uint);\\n\\n /*** Policy Hooks ***/\\n\\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);\\n function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;\\n\\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);\\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;\\n\\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);\\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external;\\n\\n function repayBorrowAllowed(\\n address cToken,\\n address payer,\\n address borrower,\\n uint repayAmount) external returns (uint);\\n function repayBorrowVerify(\\n address cToken,\\n address payer,\\n address borrower,\\n uint repayAmount,\\n uint borrowerIndex) external;\\n\\n function liquidateBorrowAllowed(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint repayAmount) external returns (uint);\\n function liquidateBorrowVerify(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n address liquidator,\\n address borrower,\\n uint repayAmount,\\n uint seizeTokens) external;\\n\\n function seizeAllowed(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint seizeTokens) external returns (uint);\\n function seizeVerify(\\n address cTokenCollateral,\\n address cTokenBorrowed,\\n address liquidator,\\n address borrower,\\n uint seizeTokens) external;\\n\\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);\\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external;\\n\\n /*** Liquidity/Liquidation Calculations ***/\\n\\n function liquidateCalculateSeizeTokens(\\n address cTokenBorrowed,\\n address cTokenCollateral,\\n uint repayAmount) external view returns (uint, uint);\\n}\\n\",\"keccak256\":\"0xede7670d2dd7b25d0187aecd2c28b7b5ca7d7c1bdac144fbedecf5d4bdd92a6b\"},\"contracts/EIP20Interface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title ERC 20 Token Standard Interface\\n * https://eips.ethereum.org/EIPS/eip-20\\n */\\ninterface EIP20Interface {\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n\\n /**\\n * @notice Get the total number of tokens in circulation\\n * @return The supply of tokens\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @notice Gets the balance of the specified address\\n * @param owner The address from which the balance will be retrieved\\n * @return The balance\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n * @return Whether or not the transfer succeeded\\n */\\n function transfer(address dst, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Transfer `amount` tokens from `src` to `dst`\\n * @param src The address of the source account\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n * @return Whether or not the transfer succeeded\\n */\\n function transferFrom(address src, address dst, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Approve `spender` to transfer up to `amount` from `src`\\n * @dev This will overwrite the approval amount for `spender`\\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\\n * @param spender The address of the account which may transfer tokens\\n * @param amount The number of tokens that are approved (-1 means infinite)\\n * @return Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Get the current allowance from `owner` for `spender`\\n * @param owner The address of the account which owns the tokens to be spent\\n * @param spender The address of the account which may transfer tokens\\n * @return The number of tokens allowed to be spent (-1 means infinite)\\n */\\n function allowance(address owner, address spender) external view returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n}\\n\",\"keccak256\":\"0xfd8ed2eac6d0b4d9ee6b32628ba68bae17544b66f190a5f7ce0c6ad024579dc8\"},\"contracts/EIP20NonStandardInterface.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title EIP20NonStandardInterface\\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\ninterface EIP20NonStandardInterface {\\n\\n /**\\n * @notice Get the total number of tokens in circulation\\n * @return The supply of tokens\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @notice Gets the balance of the specified address\\n * @param owner The address from which the balance will be retrieved\\n * @return The balance\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n ///\\n /// !!!!!!!!!!!!!!\\n /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification\\n /// !!!!!!!!!!!!!!\\n ///\\n\\n /**\\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n */\\n function transfer(address dst, uint256 amount) external;\\n\\n ///\\n /// !!!!!!!!!!!!!!\\n /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification\\n /// !!!!!!!!!!!!!!\\n ///\\n\\n /**\\n * @notice Transfer `amount` tokens from `src` to `dst`\\n * @param src The address of the source account\\n * @param dst The address of the destination account\\n * @param amount The number of tokens to transfer\\n */\\n function transferFrom(address src, address dst, uint256 amount) external;\\n\\n /**\\n * @notice Approve `spender` to transfer up to `amount` from `src`\\n * @dev This will overwrite the approval amount for `spender`\\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\\n * @param spender The address of the account which may transfer tokens\\n * @param amount The number of tokens that are approved\\n * @return Whether or not the approval succeeded\\n */\\n function approve(address spender, uint256 amount) external returns (bool success);\\n\\n /**\\n * @notice Get the current allowance from `owner` for `spender`\\n * @param owner The address of the account which owns the tokens to be spent\\n * @param spender The address of the account which may transfer tokens\\n * @return The number of tokens allowed to be spent\\n */\\n function allowance(address owner, address spender) external view returns (uint256 remaining);\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n}\\n\",\"keccak256\":\"0x9719f12e4b80b51147ac195553a198cf8b0c516e7e4d04fc324a23ed15cbafb2\"},\"contracts/ErrorReporter.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ncontract ComptrollerErrorReporter {\\n enum Error {\\n NO_ERROR,\\n UNAUTHORIZED,\\n COMPTROLLER_MISMATCH,\\n INSUFFICIENT_SHORTFALL,\\n INSUFFICIENT_LIQUIDITY,\\n INVALID_CLOSE_FACTOR,\\n INVALID_COLLATERAL_FACTOR,\\n INVALID_LIQUIDATION_INCENTIVE,\\n MARKET_NOT_ENTERED, // no longer possible\\n MARKET_NOT_LISTED,\\n MARKET_ALREADY_LISTED,\\n MATH_ERROR,\\n NONZERO_BORROW_BALANCE,\\n PRICE_ERROR,\\n REJECTION,\\n SNAPSHOT_ERROR,\\n TOO_MANY_ASSETS,\\n TOO_MUCH_REPAY\\n }\\n\\n enum FailureInfo {\\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\\n ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,\\n EXIT_MARKET_BALANCE_OWED,\\n EXIT_MARKET_REJECTION,\\n SET_CLOSE_FACTOR_OWNER_CHECK,\\n SET_CLOSE_FACTOR_VALIDATION,\\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\\n SET_COLLATERAL_FACTOR_NO_EXISTS,\\n SET_COLLATERAL_FACTOR_VALIDATION,\\n SET_COLLATERAL_FACTOR_WITHOUT_PRICE,\\n SET_IMPLEMENTATION_OWNER_CHECK,\\n SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,\\n SET_LIQUIDATION_INCENTIVE_VALIDATION,\\n SET_MAX_ASSETS_OWNER_CHECK,\\n SET_PENDING_ADMIN_OWNER_CHECK,\\n SET_PENDING_IMPLEMENTATION_OWNER_CHECK,\\n SET_PRICE_ORACLE_OWNER_CHECK,\\n SUPPORT_MARKET_EXISTS,\\n SUPPORT_MARKET_OWNER_CHECK,\\n SET_PAUSE_GUARDIAN_OWNER_CHECK\\n }\\n\\n /**\\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\\n **/\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\\n */\\n function fail(Error err, FailureInfo info) internal returns (uint) {\\n emit Failure(uint(err), uint(info), 0);\\n\\n return uint(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\\n emit Failure(uint(err), uint(info), opaqueError);\\n\\n return uint(err);\\n }\\n}\\n\\ncontract TokenErrorReporter {\\n enum Error {\\n NO_ERROR,\\n UNAUTHORIZED,\\n BAD_INPUT,\\n COMPTROLLER_REJECTION,\\n COMPTROLLER_CALCULATION_ERROR,\\n INTEREST_RATE_MODEL_ERROR,\\n INVALID_ACCOUNT_PAIR,\\n INVALID_CLOSE_AMOUNT_REQUESTED,\\n INVALID_COLLATERAL_FACTOR,\\n MATH_ERROR,\\n MARKET_NOT_FRESH,\\n MARKET_NOT_LISTED,\\n TOKEN_INSUFFICIENT_ALLOWANCE,\\n TOKEN_INSUFFICIENT_BALANCE,\\n TOKEN_INSUFFICIENT_CASH,\\n TOKEN_TRANSFER_IN_FAILED,\\n TOKEN_TRANSFER_OUT_FAILED\\n }\\n\\n /*\\n * Note: FailureInfo (but not Error) is kept in alphabetical order\\n * This is because FailureInfo grows significantly faster, and\\n * the order of Error has some meaning, while the order of FailureInfo\\n * is entirely arbitrary.\\n */\\n enum FailureInfo {\\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\\n ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\\n ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\\n ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\\n ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\\n BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n BORROW_ACCRUE_INTEREST_FAILED,\\n BORROW_CASH_NOT_AVAILABLE,\\n BORROW_FRESHNESS_CHECK,\\n BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n BORROW_MARKET_NOT_LISTED,\\n BORROW_COMPTROLLER_REJECTION,\\n LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,\\n LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,\\n LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,\\n LIQUIDATE_COMPTROLLER_REJECTION,\\n LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,\\n LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,\\n LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,\\n LIQUIDATE_FRESHNESS_CHECK,\\n LIQUIDATE_LIQUIDATOR_IS_BORROWER,\\n LIQUIDATE_REPAY_BORROW_FRESH_FAILED,\\n LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\\n LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\\n LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\\n LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,\\n LIQUIDATE_SEIZE_TOO_MUCH,\\n MINT_ACCRUE_INTEREST_FAILED,\\n MINT_COMPTROLLER_REJECTION,\\n MINT_EXCHANGE_CALCULATION_FAILED,\\n MINT_EXCHANGE_RATE_READ_FAILED,\\n MINT_FRESHNESS_CHECK,\\n MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n MINT_TRANSFER_IN_FAILED,\\n MINT_TRANSFER_IN_NOT_POSSIBLE,\\n REDEEM_ACCRUE_INTEREST_FAILED,\\n REDEEM_COMPTROLLER_REJECTION,\\n REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,\\n REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\\n REDEEM_EXCHANGE_RATE_READ_FAILED,\\n REDEEM_FRESHNESS_CHECK,\\n REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\\n REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\\n REDEEM_TRANSFER_OUT_NOT_POSSIBLE,\\n REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,\\n REDUCE_RESERVES_ADMIN_CHECK,\\n REDUCE_RESERVES_CASH_NOT_AVAILABLE,\\n REDUCE_RESERVES_FRESH_CHECK,\\n REDUCE_RESERVES_VALIDATION,\\n REPAY_BEHALF_ACCRUE_INTEREST_FAILED,\\n REPAY_BORROW_ACCRUE_INTEREST_FAILED,\\n REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_COMPTROLLER_REJECTION,\\n REPAY_BORROW_FRESHNESS_CHECK,\\n REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\\n REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,\\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\\n SET_COLLATERAL_FACTOR_VALIDATION,\\n SET_COMPTROLLER_OWNER_CHECK,\\n SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,\\n SET_INTEREST_RATE_MODEL_FRESH_CHECK,\\n SET_INTEREST_RATE_MODEL_OWNER_CHECK,\\n SET_MAX_ASSETS_OWNER_CHECK,\\n SET_ORACLE_MARKET_NOT_LISTED,\\n SET_PENDING_ADMIN_OWNER_CHECK,\\n SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,\\n SET_RESERVE_FACTOR_ADMIN_CHECK,\\n SET_RESERVE_FACTOR_FRESH_CHECK,\\n SET_RESERVE_FACTOR_BOUNDS_CHECK,\\n TRANSFER_COMPTROLLER_REJECTION,\\n TRANSFER_NOT_ALLOWED,\\n TRANSFER_NOT_ENOUGH,\\n TRANSFER_TOO_MUCH,\\n ADD_RESERVES_ACCRUE_INTEREST_FAILED,\\n ADD_RESERVES_FRESH_CHECK,\\n ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE\\n }\\n\\n /**\\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\\n **/\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\\n */\\n function fail(Error err, FailureInfo info) internal returns (uint) {\\n emit Failure(uint(err), uint(info), 0);\\n\\n return uint(err);\\n }\\n\\n /**\\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\\n */\\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\\n emit Failure(uint(err), uint(info), opaqueError);\\n\\n return uint(err);\\n }\\n}\",\"keccak256\":\"0x5179afb1071c0fd555e5c1f1d2565f72dbe1740cc3dd02f6e52037f150afc5c9\"},\"contracts/Exponential.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\nimport \\\"./CarefulMath.sol\\\";\\nimport \\\"./ExponentialNoError.sol\\\";\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author Compound\\n * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract Exponential is CarefulMath, ExponentialNoError {\\n /**\\n * @dev Creates an exponential from numerator and denominator values.\\n * Note: Returns an error if (`num` * 10e18) > MAX_INT,\\n * or if `denom` is zero.\\n */\\n function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n (MathError err1, uint rational) = divUInt(scaledNumerator, denom);\\n if (err1 != MathError.NO_ERROR) {\\n return (err1, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: rational}));\\n }\\n\\n /**\\n * @dev Adds two exponentials, returning a new exponential.\\n */\\n function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);\\n\\n return (error, Exp({mantissa: result}));\\n }\\n\\n /**\\n * @dev Subtracts two exponentials, returning a new exponential.\\n */\\n function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);\\n\\n return (error, Exp({mantissa: result}));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, returning a new Exp.\\n */\\n function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory product) = mulScalar(a, scalar);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return (MathError.NO_ERROR, truncate(product));\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory product) = mulScalar(a, scalar);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return addUInt(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Divide an Exp by a scalar, returning a new Exp.\\n */\\n function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\\n (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));\\n }\\n\\n /**\\n * @dev Divide a scalar by an Exp, returning a new Exp.\\n */\\n function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {\\n /*\\n We are doing this as:\\n getExp(mulUInt(expScale, scalar), divisor.mantissa)\\n\\n How it works:\\n Exp = a / b;\\n Scalar = s;\\n `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`\\n */\\n (MathError err0, uint numerator) = mulUInt(expScale, scalar);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n return getExp(numerator, divisor.mantissa);\\n }\\n\\n /**\\n * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.\\n */\\n function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {\\n (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);\\n if (err != MathError.NO_ERROR) {\\n return (err, 0);\\n }\\n\\n return (MathError.NO_ERROR, truncate(fraction));\\n }\\n\\n /**\\n * @dev Multiplies two exponentials, returning a new exponential.\\n */\\n function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n\\n (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);\\n if (err0 != MathError.NO_ERROR) {\\n return (err0, Exp({mantissa: 0}));\\n }\\n\\n // We add half the scale before dividing so that we get rounding instead of truncation.\\n // See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717\\n // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.\\n (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);\\n if (err1 != MathError.NO_ERROR) {\\n return (err1, Exp({mantissa: 0}));\\n }\\n\\n (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);\\n // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.\\n assert(err2 == MathError.NO_ERROR);\\n\\n return (MathError.NO_ERROR, Exp({mantissa: product}));\\n }\\n\\n /**\\n * @dev Multiplies two exponentials given their mantissas, returning a new exponential.\\n */\\n function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {\\n return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));\\n }\\n\\n /**\\n * @dev Multiplies three exponentials, returning a new exponential.\\n */\\n function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {\\n (MathError err, Exp memory ab) = mulExp(a, b);\\n if (err != MathError.NO_ERROR) {\\n return (err, ab);\\n }\\n return mulExp(ab, c);\\n }\\n\\n /**\\n * @dev Divides two exponentials, returning a new exponential.\\n * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,\\n * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)\\n */\\n function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\\n return getExp(a.mantissa, b.mantissa);\\n }\\n}\\n\",\"keccak256\":\"0x6ff054d65a0289dbb43c9f437d6909f9cf1207c9b8f984b3cb8e97a9de76a434\"},\"contracts/ExponentialNoError.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n/**\\n * @title Exponential module for storing fixed-precision decimals\\n * @author Compound\\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\\n * `Exp({mantissa: 5100000000000000000})`.\\n */\\ncontract ExponentialNoError {\\n uint constant expScale = 1e18;\\n uint constant doubleScale = 1e36;\\n uint constant halfExpScale = expScale/2;\\n uint constant mantissaOne = expScale;\\n\\n struct Exp {\\n uint mantissa;\\n }\\n\\n struct Double {\\n uint mantissa;\\n }\\n\\n /**\\n * @dev Truncates the given exp to a whole number value.\\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\\n */\\n function truncate(Exp memory exp) pure internal returns (uint) {\\n // Note: We are not using careful math here as we're performing a division that cannot fail\\n return exp.mantissa / expScale;\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\\n */\\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return truncate(product);\\n }\\n\\n /**\\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\\n */\\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\\n Exp memory product = mul_(a, scalar);\\n return add_(truncate(product), addend);\\n }\\n\\n /**\\n * @dev Checks if first Exp is less than second Exp.\\n */\\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa < right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp <= right Exp.\\n */\\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa <= right.mantissa;\\n }\\n\\n /**\\n * @dev Checks if left Exp > right Exp.\\n */\\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\\n return left.mantissa > right.mantissa;\\n }\\n\\n /**\\n * @dev returns true if Exp is exactly zero\\n */\\n function isZeroExp(Exp memory value) pure internal returns (bool) {\\n return value.mantissa == 0;\\n }\\n\\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\\n require(n < 2**224, errorMessage);\\n return uint224(n);\\n }\\n\\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\\n }\\n\\n function add_(uint a, uint b) pure internal returns (uint) {\\n return add_(a, b, \\\"addition overflow\\\");\\n }\\n\\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n uint c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\\n }\\n\\n function sub_(uint a, uint b) pure internal returns (uint) {\\n return sub_(a, b, \\\"subtraction underflow\\\");\\n }\\n\\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n\\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\\n }\\n\\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / expScale;\\n }\\n\\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\\n }\\n\\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: mul_(a.mantissa, b)});\\n }\\n\\n function mul_(uint a, Double memory b) pure internal returns (uint) {\\n return mul_(a, b.mantissa) / doubleScale;\\n }\\n\\n function mul_(uint a, uint b) pure internal returns (uint) {\\n return mul_(a, b, \\\"multiplication overflow\\\");\\n }\\n\\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n if (a == 0 || b == 0) {\\n return 0;\\n }\\n uint c = a * b;\\n require(c / a == b, errorMessage);\\n return c;\\n }\\n\\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\\n }\\n\\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\\n return Exp({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Exp memory b) pure internal returns (uint) {\\n return div_(mul_(a, expScale), b.mantissa);\\n }\\n\\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\\n }\\n\\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(a.mantissa, b)});\\n }\\n\\n function div_(uint a, Double memory b) pure internal returns (uint) {\\n return div_(mul_(a, doubleScale), b.mantissa);\\n }\\n\\n function div_(uint a, uint b) pure internal returns (uint) {\\n return div_(a, b, \\\"divide by zero\\\");\\n }\\n\\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n\\n function fraction(uint a, uint b) pure internal returns (Double memory) {\\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\\n }\\n}\\n\",\"keccak256\":\"0x7cb184b7cee71a5e707053dfba7eebbd46f11974004028100510ccce19b6694d\"},\"contracts/Governance/IINV.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\ninterface IINV {\\n function balanceOf(address) external view returns (uint);\\n function transfer(address,uint) external returns (bool);\\n function transferFrom(address,address,uint) external returns (bool);\\n function allowance(address,address) external view returns (uint);\\n function delegates(address) external view returns (address);\\n function delegate(address) external;\\n}\",\"keccak256\":\"0xaa15506bb7195da0abcf869bb4e0ad32b8906e60e0ac3cfb2d3db4bcae3c0b6e\"},\"contracts/SafeMath.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\\n// Subject to the MIT license.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, errorMessage);\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot underflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction underflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot underflow.\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, errorMessage);\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers.\\n * Reverts on division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers.\\n * Reverts with custom message on division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x6653e37ff57a02b7b7f20199bb0fd5685756ced19a67f53328b42c9d2167ffd2\"},\"contracts/XINV.sol\":{\"content\":\"pragma solidity ^0.5.16;\\n\\nimport \\\"./ComptrollerInterface.sol\\\";\\nimport \\\"./ErrorReporter.sol\\\";\\nimport \\\"./Exponential.sol\\\";\\nimport \\\"./EIP20Interface.sol\\\";\\nimport \\\"./EIP20NonStandardInterface.sol\\\";\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Governance/IINV.sol\\\";\\n/**\\n * @title xINV Core contract\\n * @notice Abstract base for xINV\\n * @author Inverse Finance\\n */\\ncontract xInvCore is Exponential, TokenErrorReporter {\\n\\n /**\\n * @dev Guard variable for re-entrancy checks\\n */\\n bool internal _notEntered;\\n\\n /**\\n * @notice EIP-20 token name for this token\\n */\\n string public name;\\n\\n /**\\n * @notice EIP-20 token symbol for this token\\n */\\n string public symbol;\\n\\n /**\\n * @notice EIP-20 token decimals for this token\\n */\\n uint8 public decimals;\\n\\n /**\\n * @notice Administrator for this contract\\n */\\n address payable public admin;\\n\\n /**\\n * @notice Pending administrator for this contract\\n */\\n address payable public pendingAdmin;\\n\\n /**\\n * @notice Contract which oversees inter-cToken operations\\n */\\n ComptrollerInterface public comptroller;\\n\\n /**\\n * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)\\n */\\n uint internal initialExchangeRateMantissa;\\n\\n /**\\n * @notice Block number that interest was last accrued at\\n */\\n uint public accrualBlockNumber;\\n\\n /**\\n * @notice Total number of tokens in circulation\\n */\\n uint public totalSupply;\\n\\n uint public rewardPerBlock;\\n\\n address public rewardTreasury;\\n\\n uint public constant borrowIndex = 1 ether; // for compatibility with Comptroller\\n\\n /**\\n * @notice Official record of token balances for each account\\n */\\n mapping (address => uint) internal accountTokens;\\n\\n /**\\n * @notice Indicator that this is a CToken contract (for inspection)\\n */\\n bool public constant isCToken = true;\\n\\n /*** Market Events ***/\\n\\n /**\\n * @notice Event emitted when tokens are minted\\n */\\n event Mint(address minter, uint mintAmount, uint mintTokens);\\n\\n /**\\n * @notice Event emitted when tokens are redeemed\\n */\\n event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);\\n\\n /*** Admin Events ***/\\n\\n /**\\n * @notice Event emitted when pendingAdmin is changed\\n */\\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\\n\\n /**\\n * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\\n */\\n event NewAdmin(address oldAdmin, address newAdmin);\\n\\n /**\\n * @notice Event emitted when comptroller is changed\\n */\\n event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);\\n\\n /**\\n * @notice Event emitted when reward treasury is changed\\n */\\n event NewRewardTreasury(address oldRewardTreasury, address newRewardTreasury);\\n\\n /**\\n * @notice Event emitted when reward per block is changed\\n */\\n event NewRewardPerBlock(uint oldRewardPerBlock, uint newRewardPerBlock);\\n\\n /**\\n * @notice EIP20 Transfer event\\n */\\n event Transfer(address indexed from, address indexed to, uint amount);\\n\\n /**\\n * @notice Failure event\\n */\\n event Failure(uint error, uint info, uint detail);\\n\\n /**\\n * @notice Initialize the money market\\n * @param comptroller_ The address of the Comptroller\\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\\n * @param name_ EIP-20 name of this token\\n * @param symbol_ EIP-20 symbol of this token\\n * @param decimals_ EIP-20 decimal precision of this token\\n */\\n function initialize(ComptrollerInterface comptroller_,\\n uint initialExchangeRateMantissa_,\\n uint rewardPerBlock_,\\n address rewardTreasury_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_) internal {\\n require(msg.sender == admin, \\\"only admin may initialize the market\\\");\\n require(accrualBlockNumber == 0, \\\"market may only be initialized once\\\");\\n\\n // Set initial exchange rate\\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\\n require(initialExchangeRateMantissa > 0, \\\"initial exchange rate must be greater than zero.\\\");\\n\\n // Set the comptroller\\n uint err = _setComptroller(comptroller_);\\n require(err == uint(Error.NO_ERROR), \\\"setting comptroller failed\\\");\\n\\n name = name_;\\n symbol = symbol_;\\n decimals = decimals_;\\n accrualBlockNumber = getBlockNumber();\\n rewardPerBlock = rewardPerBlock_;\\n rewardTreasury = rewardTreasury_;\\n\\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\\n _notEntered = true;\\n }\\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 return accountTokens[owner];\\n }\\n\\n /**\\n * @notice Get the underlying balance of the `owner`\\n * @param owner The address of the account to query\\n * @return The amount of underlying owned by `owner`\\n */\\n function balanceOfUnderlying(address owner) external returns (uint) {\\n Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});\\n (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);\\n require(mErr == MathError.NO_ERROR, \\\"balance could not be calculated\\\");\\n return balance;\\n }\\n\\n /**\\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\\n * @param account Address of the account to snapshot\\n * @return (possible error, token balance, borrow balance, exchange rate mantissa)\\n */\\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {\\n uint cTokenBalance = accountTokens[account];\\n uint exchangeRateMantissa;\\n\\n MathError mErr;\\n\\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (mErr != MathError.NO_ERROR) {\\n return (uint(Error.MATH_ERROR), 0, 0, 0);\\n }\\n\\n return (uint(Error.NO_ERROR), cTokenBalance, 0, exchangeRateMantissa);\\n }\\n\\n /**\\n * @dev Function to simply retrieve block number\\n * This exists mainly for inheriting test contracts to stub this result.\\n */\\n function getBlockNumber() internal view returns (uint) {\\n return block.number;\\n }\\n\\n /**\\n * @return Calculated exchange rate scaled by 1e18\\n */\\n function exchangeRateCurrent() public nonReentrant returns (uint) {\\n require(accrueInterest() == uint(Error.NO_ERROR), \\\"accrue interest failed\\\");\\n return exchangeRateStored();\\n }\\n\\n /**\\n * @notice Calculates the exchange rate from the underlying to the CToken\\n * @return Calculated exchange rate scaled by 1e18\\n */\\n function exchangeRateStored() public view returns (uint) {\\n (MathError err, uint result) = exchangeRateStoredInternal();\\n require(err == MathError.NO_ERROR, \\\"exchangeRateStored: exchangeRateStoredInternal failed\\\");\\n return result;\\n }\\n\\n /**\\n * @notice Calculates the exchange rate from the underlying to the CToken\\n * @return (error code, calculated exchange rate scaled by 1e18)\\n */\\n function exchangeRateStoredInternal() internal view returns (MathError, uint) {\\n uint _totalSupply = totalSupply;\\n if (_totalSupply == 0) {\\n /*\\n * If there are no tokens minted:\\n * exchangeRate = initialExchangeRate\\n */\\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\\n } else {\\n /*\\n * Otherwise:\\n * exchangeRate = totalCash / totalSupply\\n */\\n uint totalCash = getCashPrior();\\n Exp memory exchangeRate;\\n MathError mathErr;\\n\\n (mathErr, exchangeRate) = getExp(totalCash, _totalSupply);\\n if (mathErr != MathError.NO_ERROR) {\\n return (mathErr, 0);\\n }\\n\\n return (MathError.NO_ERROR, exchangeRate.mantissa);\\n }\\n }\\n\\n /**\\n * @notice Get cash balance of this cToken in the underlying asset\\n * @return The quantity of underlying asset owned by this contract\\n */\\n function getCash() external view returns (uint) {\\n return getCashPrior();\\n }\\n\\n // brings rewards from treasury into this contract\\n function accrueInterest() public returns (uint) {\\n /* Remember the initial block number */\\n uint currentBlockNumber = getBlockNumber();\\n uint accrualBlockNumberPrior = accrualBlockNumber;\\n\\n /* Short-circuit accumulating 0 interest */\\n if (accrualBlockNumberPrior == currentBlockNumber) {\\n return uint(Error.NO_ERROR);\\n }\\n\\n /* Calculate the number of blocks elapsed since the last accrual */\\n (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);\\n require(mathErr == MathError.NO_ERROR, \\\"could not calculate block delta\\\");\\n \\n /* Calculate accumulated reward amount */\\n uint reward;\\n \\n (mathErr, reward) = mulUInt(rewardPerBlock, blockDelta);\\n require(mathErr == MathError.NO_ERROR, \\\"could not calculate reward\\\");\\n\\n if(totalSupply > 0 && rewardTreasury != address(0) && canTransferIn(rewardTreasury, reward)) {\\n doTransferIn(rewardTreasury, reward);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n accrualBlockNumber = currentBlockNumber;\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Sender supplies assets into the market and receives cTokens in exchange\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\\n */\\n function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\\n return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);\\n }\\n // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\\n return mintFresh(msg.sender, mintAmount);\\n }\\n\\n struct MintLocalVars {\\n Error err;\\n MathError mathErr;\\n uint exchangeRateMantissa;\\n uint mintTokens;\\n uint totalSupplyNew;\\n uint accountTokensNew;\\n uint actualMintAmount;\\n }\\n\\n /**\\n * @notice User supplies assets into the market and receives cTokens in exchange\\n * @param minter The address of the account which is supplying the assets\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\\n */\\n function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {\\n /* Fail if mint not allowed */\\n uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);\\n if (allowed != 0) {\\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);\\n }\\n\\n MintLocalVars memory vars;\\n\\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /*\\n * We call `doTransferIn` for the minter and the mintAmount.\\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\\n * `doTransferIn` reverts if anything goes wrong, since we can't be sure if\\n * side-effects occurred. The function returns the amount actually transferred,\\n * in case of a fee. On success, the cToken holds an additional `actualMintAmount`\\n * of cash.\\n */\\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\\n\\n /*\\n * We get the current exchange rate and calculate the number of cTokens to be minted:\\n * mintTokens = actualMintAmount / exchangeRate\\n */\\n\\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_EXCHANGE_CALCULATION_FAILED\\\");\\n\\n /*\\n * We calculate the new total supply of cTokens and minter token balance, checking for overflow:\\n * totalSupplyNew = totalSupply + mintTokens\\n * accountTokensNew = accountTokens[minter] + mintTokens\\n */\\n (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED\\\");\\n require(vars.totalSupplyNew < 2**96, \\\"MINT_NEW_TOTAL_SUPPLY_OVER_CAPACITY\\\");\\n\\n (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);\\n require(vars.mathErr == MathError.NO_ERROR, \\\"MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED\\\");\\n\\n /* We write previously calculated values into storage */\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[minter] = vars.accountTokensNew;\\n\\n /* We emit a Mint event, and a Transfer event */\\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\\n emit Transfer(address(this), minter, vars.mintTokens);\\n\\n /* we move delegates */\\n _moveDelegates(address(0), delegates[minter], uint96(vars.mintTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);\\n\\n return (uint(Error.NO_ERROR), vars.actualMintAmount);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for the underlying asset\\n * @param redeemTokens The number of cTokens to redeem into underlying\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemInternal(uint redeemTokens, bool useEscrow) internal nonReentrant returns (uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\\n return redeemFresh(msg.sender, redeemTokens, 0, useEscrow);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\\n * @param redeemAmount The amount of underlying to receive from redeeming cTokens\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemUnderlyingInternal(uint redeemAmount, bool useEscrow) internal nonReentrant returns (uint) {\\n uint error = accrueInterest();\\n if (error != uint(Error.NO_ERROR)) {\\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\\n }\\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\\n return redeemFresh(msg.sender, 0, redeemAmount, useEscrow);\\n }\\n\\n struct RedeemLocalVars {\\n Error err;\\n MathError mathErr;\\n uint exchangeRateMantissa;\\n uint redeemTokens;\\n uint redeemAmount;\\n uint totalSupplyNew;\\n uint accountTokensNew;\\n }\\n\\n /**\\n * @notice User redeems cTokens in exchange for the underlying asset\\n * @param redeemer The address of the account which is redeeming the tokens\\n * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn, bool useEscrow) internal returns (uint) {\\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \\\"one of redeemTokensIn or redeemAmountIn must be zero\\\");\\n\\n RedeemLocalVars memory vars;\\n\\n /* exchangeRate = invoke Exchange Rate Stored() */\\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));\\n }\\n\\n /* If redeemTokensIn > 0: */\\n if (redeemTokensIn > 0) {\\n /*\\n * We calculate the exchange rate and the amount of underlying to be redeemed:\\n * redeemTokens = redeemTokensIn\\n * redeemAmount = redeemTokensIn x exchangeRateCurrent\\n */\\n vars.redeemTokens = redeemTokensIn;\\n\\n (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n } else {\\n /*\\n * We get the current exchange rate and calculate the amount to be redeemed:\\n * redeemTokens = redeemAmountIn / exchangeRate\\n * redeemAmount = redeemAmountIn\\n */\\n\\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n vars.redeemAmount = redeemAmountIn;\\n }\\n\\n /* Fail if redeem not allowed */\\n uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);\\n if (allowed != 0) {\\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);\\n }\\n\\n /*\\n * We calculate the new total supply and redeemer balance, checking for underflow:\\n * totalSupplyNew = totalSupply - redeemTokens\\n * accountTokensNew = accountTokens[redeemer] - redeemTokens\\n */\\n (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);\\n if (vars.mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\\n }\\n\\n /* Fail gracefully if protocol has insufficient cash */\\n if (getCashPrior() < vars.redeemAmount) {\\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /*\\n * We invoke doTransferOut for the redeemer and the redeemAmount.\\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\\n * On success, the cToken has redeemAmount less of cash.\\n * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\\n */\\n doTransferOut(redeemer, vars.redeemAmount, useEscrow);\\n\\n /* We write previously calculated values into storage */\\n totalSupply = vars.totalSupplyNew;\\n accountTokens[redeemer] = vars.accountTokensNew;\\n\\n /* We emit a Transfer event, and a Redeem event */\\n emit Transfer(redeemer, address(this), vars.redeemTokens);\\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n /* We move delegates */\\n _moveDelegates(delegates[redeemer], address(0), uint96(vars.redeemTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Transfers collateral tokens (this market) to the liquidator.\\n * @dev Will fail unless called by another cToken during the process of liquidation.\\n * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\\n * @param liquidator The account receiving seized collateral\\n * @param borrower The account having collateral seized\\n * @param seizeTokens The number of cTokens to seize\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {\\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\\n }\\n\\n /**\\n * @notice Transfers collateral tokens (this market) to the liquidator.\\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.\\n * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.\\n * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)\\n * @param liquidator The account receiving seized collateral\\n * @param borrower The account having collateral seized\\n * @param seizeTokens The number of cTokens to seize\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {\\n /* Fail if seize not allowed */\\n uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);\\n if (allowed != 0) {\\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);\\n }\\n\\n /* Fail if borrower = liquidator */\\n if (borrower == liquidator) {\\n return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);\\n }\\n\\n MathError mathErr;\\n uint borrowerTokensNew;\\n uint liquidatorTokensNew;\\n\\n /*\\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\\n */\\n (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));\\n }\\n\\n (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);\\n if (mathErr != MathError.NO_ERROR) {\\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));\\n }\\n\\n /////////////////////////\\n // EFFECTS & INTERACTIONS\\n // (No safe failures beyond this point)\\n\\n /* We write the previously calculated values into storage */\\n accountTokens[borrower] = borrowerTokensNew;\\n accountTokens[liquidator] = liquidatorTokensNew;\\n\\n /* Emit a Transfer event */\\n emit Transfer(borrower, liquidator, seizeTokens);\\n\\n /* We move delegates to liquidator although they'll be burned in the redeemFresh call after */\\n _moveDelegates(delegates[borrower], delegates[liquidator], uint96(seizeTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n\\n /* We call the defense hook */\\n comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);\\n\\n // Auto-redeem liquidator and skip escrow (cast liquidator to payable)\\n redeemFresh(address(uint160(liquidator)), seizeTokens, 0, false);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n\\n /*** Admin Functions ***/\\n\\n /**\\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\\n * @param newPendingAdmin New pending admin.\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {\\n // Check caller = admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);\\n }\\n\\n // Save current value, if any, for inclusion in log\\n address oldPendingAdmin = pendingAdmin;\\n\\n // Store pendingAdmin with value newPendingAdmin\\n pendingAdmin = newPendingAdmin;\\n\\n // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)\\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\\n * @dev Admin function for pending admin to accept role and update admin\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _acceptAdmin() external returns (uint) {\\n // Check caller is pendingAdmin and pendingAdmin \\u2260 address(0)\\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);\\n }\\n\\n // Save current values for inclusion in log\\n address oldAdmin = admin;\\n address oldPendingAdmin = pendingAdmin;\\n\\n // Store admin with value pendingAdmin\\n admin = pendingAdmin;\\n\\n // Clear the pending value\\n pendingAdmin = address(0);\\n\\n emit NewAdmin(oldAdmin, admin);\\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n /**\\n * @notice Sets a new comptroller for the market\\n * @dev Admin function to set a new comptroller\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n\\n ComptrollerInterface oldComptroller = comptroller;\\n // Ensure invoke comptroller.isComptroller() returns true\\n require(newComptroller.isComptroller(), \\\"marker method returned false\\\");\\n\\n // Set market's comptroller to newComptroller\\n comptroller = newComptroller;\\n\\n // Emit NewComptroller(oldComptroller, newComptroller)\\n emit NewComptroller(oldComptroller, newComptroller);\\n\\n return uint(Error.NO_ERROR);\\n }\\n\\n function _setRewardTreasury(address newRewardTreasury) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n \\n address oldRewardTreasury = rewardTreasury;\\n rewardTreasury = newRewardTreasury; // it's acceptable to set it as address(0)\\n\\n emit NewRewardTreasury(oldRewardTreasury, newRewardTreasury);\\n }\\n\\n function _setRewardPerBlock(uint newRewardPerBlock) public returns (uint) {\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n\\n uint oldRewardPerBlock = rewardPerBlock;\\n rewardPerBlock = newRewardPerBlock; // it's acceptable to set it as 0\\n\\n emit NewRewardPerBlock(oldRewardPerBlock, newRewardPerBlock);\\n\\n }\\n\\n /*** Safe Token ***/\\n\\n /**\\n * @notice Gets balance of this contract in terms of the underlying\\n * @dev This excludes the value of the current message, if any\\n * @return The quantity of underlying owned by this contract\\n */\\n function getCashPrior() internal view returns (uint);\\n\\n /**\\n * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.\\n * This may revert due to insufficient balance or insufficient allowance.\\n */\\n function doTransferIn(address from, uint amount) internal returns (uint);\\n\\n function canTransferIn(address from, uint amount) internal view returns (bool);\\n \\n /**\\n * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.\\n * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.\\n * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.\\n */\\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal;\\n\\n\\n /*** Reentrancy Guard ***/\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n */\\n modifier nonReentrant() {\\n require(_notEntered, \\\"re-entered\\\");\\n _notEntered = false;\\n _;\\n _notEntered = true; // get a gas-refund post-Istanbul\\n }\\n\\n /*** Delegation ***/\\n \\n /// @notice A record of each accounts delegate\\n mapping (address => address) public delegates;\\n\\n /// @notice A checkpoint for marking number of votes from a given block\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 votes;\\n }\\n\\n /// @notice A record of votes checkpoints for each account, by index\\n mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;\\n\\n /// @notice The number of checkpoints for each account\\n mapping (address => uint32) public numCheckpoints;\\n\\n /// @notice An event thats emitted when an account changes its delegate\\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\\n\\n /// @notice An event thats emitted when a delegate account's vote balance changes\\n event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);\\n\\n /**\\n * @notice Gets the current votes balance for `account`\\n * @param account The address to get votes balance\\n * @return The number of current votes for `account`\\n */\\n function getCurrentVotes(address account) external view returns (uint96) {\\n uint32 nCheckpoints = numCheckpoints[account];\\n return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\\n }\\n\\n /**\\n * @notice Determine the prior number of votes for an account as of a block number\\n * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\\n * @param account The address of the account to check\\n * @param blockNumber The block number to get the vote balance at\\n * @return The number of votes the account had as of the given block\\n */\\n function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {\\n require(blockNumber < block.number, \\\"INV::getPriorVotes: not yet determined\\\");\\n\\n uint32 nCheckpoints = numCheckpoints[account];\\n if (nCheckpoints == 0) {\\n return 0;\\n }\\n\\n // First check most recent balance\\n if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\\n return checkpoints[account][nCheckpoints - 1].votes;\\n }\\n\\n // Next check implicit zero balance\\n if (checkpoints[account][0].fromBlock > blockNumber) {\\n return 0;\\n }\\n\\n uint32 lower = 0;\\n uint32 upper = nCheckpoints - 1;\\n while (upper > lower) {\\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\\n Checkpoint memory cp = checkpoints[account][center];\\n if (cp.fromBlock == blockNumber) {\\n return cp.votes;\\n } else if (cp.fromBlock < blockNumber) {\\n lower = center;\\n } else {\\n upper = center - 1;\\n }\\n }\\n return checkpoints[account][lower].votes;\\n }\\n\\n function _delegate(address delegator, address delegatee) internal {\\n address currentDelegate = delegates[delegator];\\n uint96 delegatorBalance = uint96(accountTokens[delegator]); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\\n delegates[delegator] = delegatee;\\n\\n emit DelegateChanged(delegator, currentDelegate, delegatee);\\n\\n _moveDelegates(currentDelegate, delegatee, delegatorBalance);\\n }\\n\\n function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {\\n if (srcRep != dstRep && amount > 0) {\\n if (srcRep != address(0)) {\\n uint32 srcRepNum = numCheckpoints[srcRep];\\n uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\\n uint96 srcRepNew = sub96(srcRepOld, amount, \\\"INV::_moveVotes: vote amount underflows\\\");\\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\\n }\\n\\n if (dstRep != address(0)) {\\n uint32 dstRepNum = numCheckpoints[dstRep];\\n uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\\n uint96 dstRepNew = add96(dstRepOld, amount, \\\"INV::_moveVotes: vote amount overflows\\\");\\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\\n }\\n }\\n }\\n\\n function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {\\n uint32 blockNumber = safe32(block.number, \\\"INV::_writeCheckpoint: block number exceeds 32 bits\\\");\\n\\n if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\\n } else {\\n checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\\n numCheckpoints[delegatee] = nCheckpoints + 1;\\n }\\n\\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\\n }\\n\\n function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {\\n require(n < 2**32, errorMessage);\\n return uint32(n);\\n }\\n\\n function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\\n uint96 c = a + b;\\n require(c >= a, errorMessage);\\n return c;\\n }\\n\\n function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n}\\n\\ncontract TimelockEscrow {\\n using SafeMath for uint;\\n\\n address public underlying;\\n address public governance;\\n address public market;\\n uint public duration = 10 days;\\n mapping (address => EscrowData) public pendingWithdrawals;\\n\\n struct EscrowData {\\n uint withdrawalTimestamp;\\n uint amount;\\n }\\n\\n constructor(address underlying_, address governance_) public {\\n underlying = underlying_;\\n governance = governance_;\\n market = msg.sender;\\n }\\n\\n // set to 0 to send funds directly to users\\n function _setEscrowDuration(uint duration_) public {\\n require(msg.sender == governance, \\\"only governance can set escrow duration\\\");\\n duration = duration_;\\n }\\n\\n function _setGov(address governance_) public {\\n require(msg.sender == governance, \\\"only governance can set its new address\\\");\\n governance = governance_;\\n }\\n\\n /**\\n * @notice assumes funds were already sent to this contract by the market. Resets escrow timelock on each withdrawal\\n */\\n function escrow(address user, uint amount) public {\\n require(msg.sender == market, \\\"only market can escrow\\\");\\n if(duration > 0) {\\n EscrowData memory withdrawal = pendingWithdrawals[user];\\n pendingWithdrawals[user] = EscrowData({\\n // we set the future withdrawal timestamp based on current `duration` to avoid applying future `duration` changes to existing withdrawals in the event of a governance attack\\n withdrawalTimestamp: block.timestamp + duration,\\n amount: withdrawal.amount.add(amount)\\n });\\n emit Escrow(user, block.timestamp + duration, amount);\\n } else { // if duration is 0, we send the funds directly to the user\\n EIP20Interface token = EIP20Interface(underlying);\\n token.transfer(user, amount);\\n }\\n }\\n\\n /**\\n * @notice returns user withdrawable amount\\n */\\n function withdrawable(address user) public view returns (uint amount) {\\n EscrowData memory withdrawal = pendingWithdrawals[user];\\n if(withdrawal.withdrawalTimestamp <= block.timestamp) {\\n amount = withdrawal.amount;\\n }\\n }\\n\\n function withdraw() public {\\n uint amount = withdrawable(msg.sender);\\n require(amount > 0, \\\"Nothing to withdraw\\\");\\n EIP20Interface token = EIP20Interface(underlying);\\n delete pendingWithdrawals[msg.sender];\\n token.transfer(msg.sender, amount);\\n emit Withdraw(msg.sender, amount);\\n }\\n\\n event Escrow(address to, uint withdrawalTimestamp, uint amount);\\n event Withdraw(address to, uint amount);\\n}\\n\\n/**\\n * @title xINV contract\\n * @notice wraps INV token\\n * @author Inverse Finance\\n */\\ncontract XINV is xInvCore {\\n\\n address public underlying;\\n TimelockEscrow public escrow;\\n\\n /**\\n * @notice Construct the xINV market\\n * @param underlying_ The address of the underlying asset\\n * @param comptroller_ The address of the Comptroller\\n * @param name_ ERC-20 name of this token\\n * @param symbol_ ERC-20 symbol of this token\\n * @param decimals_ ERC-20 decimal precision of this token\\n * @param admin_ Address of the administrator of this token\\n */\\n constructor(address underlying_,\\n ComptrollerInterface comptroller_,\\n uint rewardPerBlock_, \\n address rewardTreasury_,\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_,\\n address payable admin_) public {\\n // Creator of the contract is admin during initialization\\n admin = msg.sender;\\n\\n // CToken initialize does the bulk of the work\\n super.initialize(comptroller_, 1e18, rewardPerBlock_, rewardTreasury_, name_, symbol_, decimals_);\\n\\n // Set underlying and sanity check it\\n underlying = underlying_;\\n EIP20Interface(underlying).totalSupply();\\n\\n // Set the proper admin now that initialization is done\\n admin = admin_;\\n\\n // Create escrow contract\\n escrow = new TimelockEscrow(underlying_, admin_);\\n }\\n\\n /*** User Interface ***/\\n\\n /**\\n * @notice Sync user delegate from INV\\n * @param user Address to sync\\n */\\n function syncDelegate(address user) public {\\n address invDelegate = IINV(underlying).delegates(user);\\n _delegate(user, invDelegate);\\n }\\n\\n /**\\n * @notice Sender supplies assets into the market and receives cTokens in exchange\\n * @param mintAmount The amount of the underlying asset to supply\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function mint(uint mintAmount) external returns (uint) {\\n (uint err,) = mintInternal(mintAmount);\\n \\n /* we inherit delegate from INV */\\n address invDelegate = IINV(underlying).delegates(msg.sender);\\n if(delegates[msg.sender] != invDelegate) {\\n _delegate(msg.sender, invDelegate);\\n }\\n return err;\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for the underlying asset\\n * @param redeemTokens The number of cTokens to redeem into underlying\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeem(uint redeemTokens) external returns (uint) {\\n return redeemInternal(redeemTokens, true);\\n }\\n\\n /**\\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\\n * @param redeemAmount The amount of underlying to redeem\\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\\n */\\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\\n return redeemUnderlyingInternal(redeemAmount, true);\\n }\\n\\n /*** Safe Token ***/\\n\\n /**\\n * @notice Gets balance of this contract in terms of the underlying\\n * @dev This excludes the value of the current message, if any\\n * @return The quantity of underlying tokens owned by this contract\\n */\\n function getCashPrior() internal view returns (uint) {\\n EIP20Interface token = EIP20Interface(underlying);\\n return token.balanceOf(address(this));\\n }\\n\\n /**\\n * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.\\n * This will revert due to insufficient balance or insufficient allowance.\\n * This function returns the actual amount received,\\n * which may be less than `amount` if there is a fee attached to the transfer.\\n *\\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\n function doTransferIn(address from, uint amount) internal returns (uint) {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));\\n token.transferFrom(from, address(this), amount);\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 { // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 { // This is a compliant ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default { // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"TOKEN_TRANSFER_IN_FAILED\\\");\\n\\n // Calculate the amount that was *actually* transferred\\n uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));\\n require(balanceAfter >= balanceBefore, \\\"TOKEN_TRANSFER_IN_OVERFLOW\\\");\\n return balanceAfter - balanceBefore; // underflow already checked above, just subtract\\n }\\n\\n /**\\n * @dev returns true if `from` has sufficient allowance and balance to to send `amount` to this address\\n */\\n function canTransferIn(address from, uint amount) internal view returns (bool) {\\n EIP20Interface token = EIP20Interface(underlying);\\n uint balance = token.balanceOf(from);\\n uint allowance = token.allowance(from, address(this));\\n return balance >= amount && allowance >= amount;\\n }\\n\\n /**\\n * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory\\n * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to\\n * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified\\n * it is >= amount, this should not revert in normal conditions.\\n *\\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\\n */\\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal {\\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\\n if(useEscrow) {\\n token.transfer(address(escrow), amount);\\n } else {\\n token.transfer(to, amount);\\n }\\n\\n bool success;\\n assembly {\\n switch returndatasize()\\n case 0 { // This is a non-standard ERC-20\\n success := not(0) // set success to true\\n }\\n case 32 { // This is a complaint ERC-20\\n returndatacopy(0, 0, 32)\\n success := mload(0) // Set `success = returndata` of external call\\n }\\n default { // This is an excessively non-compliant ERC-20, revert.\\n revert(0, 0)\\n }\\n }\\n require(success, \\\"TOKEN_TRANSFER_OUT_FAILED\\\");\\n if(useEscrow) {\\n escrow.escrow(to, amount);\\n }\\n }\\n\\n function _setTimelockEscrow(TimelockEscrow newTimelockEscrow) public returns (uint) {\\n require(newTimelockEscrow.market() == address(this), \\\"sanity check: newTimelockEscrow must use this market\\\");\\n // Check caller is admin\\n if (msg.sender != admin) {\\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\\n }\\n \\n TimelockEscrow oldTimelockEscrow = escrow;\\n escrow = newTimelockEscrow;\\n\\n emit NewTimelockEscrow(oldTimelockEscrow, newTimelockEscrow);\\n }\\n\\n event NewTimelockEscrow(TimelockEscrow oldTimelockEscrow, TimelockEscrow newTimelockEscrow);\\n}\",\"keccak256\":\"0x19ba5d62d002dea97ebdb8cc87220bbfb4771b6e8d741a4af8293258dfb5eb46\"}},\"version\":1}", + "bytecode": "0x60806040523480156200001157600080fd5b50604051620048073803806200480783398181016040526101008110156200003857600080fd5b81516020830151604080850151606086015160808701805193519597949692959194919392820192846401000000008211156200007457600080fd5b9083019060208201858111156200008a57600080fd5b8251640100000000811182820188101715620000a557600080fd5b82525081516020918201929091019080838360005b83811015620000d4578181015183820152602001620000ba565b50505050905090810190601f168015620001025780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200012657600080fd5b9083019060208201858111156200013c57600080fd5b82516401000000008111828201881017156200015757600080fd5b82525081516020918201929091019080838360005b83811015620001865781810151838201526020016200016c565b50505050905090810190601f168015620001b45780820380516001836020036101000a031916815260200191505b506040908152602082810151929091015160038054610100600160a81b03191633610100021790559193509091506200020c908890670de0b6b3a764000090899089908990899089906200032d811b620033b417901c565b600f80546001600160a01b0319166001600160a01b038a81169190911791829055604080516318160ddd60e01b8152905192909116916318160ddd91600480820192602092909190829003018186803b1580156200026957600080fd5b505afa1580156200027e573d6000803e3d6000fd5b505050506040513d60208110156200029557600080fd5b505060038054610100600160a81b0319166101006001600160a01b0384160217905560405188908290620002c990620006cc565b6001600160a01b03928316815291166020820152604080519182900301906000f080158015620002fd573d6000803e3d6000fd5b50601080546001600160a01b0319166001600160a01b0392909216919091179055506200077c9650505050505050565b60035461010090046001600160a01b031633146200037d5760405162461bcd60e51b8152600401808060200182810382526024815260200180620047906024913960400191505060405180910390fd5b60075415620003be5760405162461bcd60e51b8152600401808060200182810382526023815260200180620047b46023913960400191505060405180910390fd5b600686905585620004015760405162461bcd60e51b8152600401808060200182810382526030815260200180620047d76030913960400191505060405180910390fd5b600062000417886001600160e01b03620004f016565b905080156200046d576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b835162000482906001906020870190620006da565b50825162000498906002906020860190620006da565b506003805460ff191660ff8416179055620004b262000657565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b60035460009061010090046001600160a01b031633146200052a57620005226001603f6001600160e01b036200065c16565b905062000652565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b1580156200057057600080fd5b505afa15801562000585573d6000803e3d6000fd5b505050506040513d60208110156200059c57600080fd5b5051620005f0576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160009150505b919050565b435b90565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360108111156200068c57fe5b8360508111156200069957fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115620006c557fe5b9392505050565b6107a88062003fe883390190565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200071d57805160ff19168380011785556200074d565b828001600101855582156200074d579182015b828111156200074d57825182559160200191906001019062000730565b506200075b9291506200075f565b5090565b6200065991905b808211156200075b576000815560010162000766565b61385c806200078c6000396000f3fe608060405234801561001057600080fd5b50600436106102275760003560e01c8063852a12e311610130578063b71d1a0c116100b8578063e2fdcc171161007c578063e2fdcc1714610632578063e9c714f21461063a578063f1127ed814610642578063f851a4401461069c578063fe9c44ae146106a457610227565b8063b71d1a0c14610593578063bd6d894d146105b9578063c37f68e2146105c1578063c7c934a11461060d578063db006a751461061557610227565b8063a0712d68116100ff578063a0712d681461050a578063a6afed9514610527578063aa5af0fd1461052f578063b2a02ff114610537578063b4b5ea571461056d57610227565b8063852a12e3146104c05780638aa1c05f146104dd5780638ae39cac146104fa57806395d89b411461050257610227565b80633b1d21a2116101b35780636c540baf116101825780636c540baf146104035780636f307dc31461040b5780636fcfff451461041357806370a0823114610452578063782d6fe11461047857610227565b80633b1d21a2146103a75780634576b5db146103af578063587cde1e146103d55780635fe3b567146103fb57610227565b8063182df0f5116101fa578063182df0f51461030f5780631e756d0f14610317578063267822471461033f578063313ce567146103635780633af9e6691461038157610227565b806306fdde031461022c5780630c19dc3a146102a957806317c50d06146102e157806318160ddd14610307575b600080fd5b6102346106c0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561026e578181015183820152602001610256565b50505050905090810190601f16801561029b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102cf600480360360208110156102bf57600080fd5b50356001600160a01b031661074d565b60408051918252519081900360200190f35b6102cf600480360360208110156102f757600080fd5b50356001600160a01b0316610893565b6102cf61091e565b6102cf610924565b61033d6004803603602081101561032d57600080fd5b50356001600160a01b0316610987565b005b610347610a14565b604080516001600160a01b039092168252519081900360200190f35b61036b610a23565b6040805160ff9092168252519081900360200190f35b6102cf6004803603602081101561039757600080fd5b50356001600160a01b0316610a2c565b6102cf610ae2565b6102cf600480360360208110156103c557600080fd5b50356001600160a01b0316610af1565b610347600480360360208110156103eb57600080fd5b50356001600160a01b0316610c3f565b610347610c5a565b6102cf610c69565b610347610c6f565b6104396004803603602081101561042957600080fd5b50356001600160a01b0316610c7e565b6040805163ffffffff9092168252519081900360200190f35b6102cf6004803603602081101561046857600080fd5b50356001600160a01b0316610c96565b6104a46004803603604081101561048e57600080fd5b506001600160a01b038135169060200135610cb1565b604080516001600160601b039092168252519081900360200190f35b6102cf600480360360208110156104d657600080fd5b5035610edf565b6102cf600480360360208110156104f357600080fd5b5035610eec565b6102cf610f5b565b610234610f61565b6102cf6004803603602081101561052057600080fd5b5035610fb9565b6102cf611079565b6102cf6111e9565b6102cf6004803603606081101561054d57600080fd5b506001600160a01b038135811691602081013590911690604001356111f5565b6104a46004803603602081101561058357600080fd5b50356001600160a01b0316611266565b6102cf600480360360208110156105a957600080fd5b50356001600160a01b03166112d8565b6102cf611364565b6105e7600480360360208110156105d757600080fd5b50356001600160a01b0316611420565b604080519485526020850193909352838301919091526060830152519081900360800190f35b61034761148d565b6102cf6004803603602081101561062b57600080fd5b503561149c565b6103476114a9565b6102cf6114b8565b6106746004803603604081101561065857600080fd5b5080356001600160a01b0316906020013563ffffffff166115bb565b6040805163ffffffff90931683526001600160601b0390911660208301528051918290030190f35b6103476115f0565b6106ac611604565b604080519115158252519081900360200190f35b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156107455780601f1061071a57610100808354040283529160200191610745565b820191906000526020600020905b81548152906001019060200180831161072857829003601f168201915b505050505081565b6000306001600160a01b0316826001600160a01b03166380f556056040518163ffffffff1660e01b815260040160206040518083038186803b15801561079257600080fd5b505afa1580156107a6573d6000803e3d6000fd5b505050506040513d60208110156107bc57600080fd5b50516001600160a01b0316146108035760405162461bcd60e51b81526004018080602001828103825260348152602001806136e66034913960400191505060405180910390fd5b60035461010090046001600160a01b0316331461082d576108266001603f611609565b905061088e565b601080546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f8a0324ea550ac953d4515436f05889f90a816b559ca26ee450b104d4d5a248fa929181900390910190a1505b919050565b60035460009061010090046001600160a01b031633146108b9576108266001603f611609565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f2856afeddd63e06a55f7d242638b9ce830a95d17f6ac86997a9acd7de2761628929181900390910190a150919050565b60085481565b600080600061093161166f565b9092509050600082600381111561094457fe5b146109805760405162461bcd60e51b815260040180806020018281038252603581526020018061374d6035913960400191505060405180910390fd5b9150505b90565b600f5460408051632c3e6f0f60e11b81526001600160a01b0384811660048301529151600093929092169163587cde1e91602480820192602092909190829003018186803b1580156109d857600080fd5b505afa1580156109ec573d6000803e3d6000fd5b505050506040513d6020811015610a0257600080fd5b50519050610a1082826116e4565b5050565b6004546001600160a01b031681565b60035460ff1681565b6000610a3661334c565b6040518060200160405280610a49611364565b90526001600160a01b0384166000908152600b6020526040812054919250908190610a75908490611764565b90925090506000826003811115610a8857fe5b14610ada576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610aec6117b8565b905090565b60035460009061010090046001600160a01b03163314610b17576108266001603f611609565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610b5c57600080fd5b505afa158015610b70573d6000803e3d6000fd5b505050506040513d6020811015610b8657600080fd5b5051610bd9576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600c602052600090815260409020546001600160a01b031681565b6005546001600160a01b031681565b60075481565b600f546001600160a01b031681565b600e6020526000908152604090205463ffffffff1681565b6001600160a01b03166000908152600b602052604090205490565b6000438210610cf15760405162461bcd60e51b815260040180806020018281038252602681526020018061363f6026913960400191505060405180910390fd5b6001600160a01b0383166000908152600e602052604090205463ffffffff1680610d1f576000915050610ed9565b6001600160a01b0384166000908152600d6020908152604080832063ffffffff600019860181168552925290912054168310610d9b576001600160a01b0384166000908152600d602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050610ed9565b6001600160a01b0384166000908152600d6020908152604080832083805290915290205463ffffffff16831015610dd6576000915050610ed9565b600060001982015b8163ffffffff168163ffffffff161115610e9957600282820363ffffffff16048103610e0861335f565b506001600160a01b0387166000908152600d6020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b03169181019190915290871415610e7457602001519450610ed99350505050565b805163ffffffff16871115610e8b57819350610e92565b6001820392505b5050610dde565b506001600160a01b0385166000908152600d6020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b6000610ed9826001611838565b60035460009061010090046001600160a01b03163314610f12576108266001603f611609565b6009805490839055604080518281526020810185905281517f3b7a406bf2b66d0f83f6b1cf4c39edf1269cad80712b94cd80a44d13f61f1357929181900390910190a150919050565b60095481565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156107455780601f1061071a57610100808354040283529160200191610745565b600080610fc5836118d9565b50600f5460408051632c3e6f0f60e11b815233600482015290519293506000926001600160a01b039092169163587cde1e91602480820192602092909190829003018186803b15801561101757600080fd5b505afa15801561102b573d6000803e3d6000fd5b505050506040513d602081101561104157600080fd5b5051336000908152600c60205260409020549091506001600160a01b038083169116146110725761107233826116e4565b5092915050565b600080611084611981565b6007549091508082141561109d57600092505050610984565b6000806110aa8484611985565b909250905060008260038111156110bd57fe5b1461110f576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b600061111d600954836119a8565b9093509050600083600381111561113057fe5b14611182576040805162461bcd60e51b815260206004820152601a60248201527f636f756c64206e6f742063616c63756c61746520726577617264000000000000604482015290519081900360640190fd5b600060085411801561119e5750600a546001600160a01b031615155b80156111bb5750600a546111bb906001600160a01b0316826119e7565b156111d857600a546111d6906001600160a01b031682611b06565b505b600785905560009550505050505090565b670de0b6b3a764000081565b6000805460ff1661123a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561125033858585611d50565b90506000805460ff191660011790559392505050565b6001600160a01b0381166000908152600e602052604081205463ffffffff1680611291576000610c38565b6001600160a01b0383166000908152600d6020908152604080832063ffffffff60001986011684529091529020546001600160601b03600160201b90910416915050919050565b60035460009061010090046001600160a01b031633146112fe5761082660016045611609565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610c38565b6000805460ff166113a9576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556113bb611079565b14611406576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b61140e610924565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600b6020526040812054819081908190818061144961166f565b92509050600081600381111561145b57fe5b1461147757600996506000955085945084935061148692505050565b60009650919450600093509150505b9193509193565b600a546001600160a01b031681565b6000610ed982600161200e565b6010546001600160a01b031681565b6004546000906001600160a01b0316331415806114d3575033155b156114eb576114e460016000611609565b9050610984565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600d60209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b60035461010090046001600160a01b031681565b600181565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561163857fe5b83605081111561164457fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610c3857fe5b60085460009081908061168a575050600654600091506116e0565b60006116946117b8565b905061169e61334c565b60006116aa8385612089565b9250905060008160038111156116bc57fe5b146116d0579450600093506116e092505050565b50516000945092506116e0915050565b9091565b6001600160a01b038083166000818152600c602081815260408084208054600b845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a461175e828483612139565b50505050565b600080600061177161334c565b61177b86866122d4565b9092509050600082600381111561178e57fe5b1461179f57509150600090506117b1565b60006117aa8261233c565b9350935050505b9250929050565b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b15801561180657600080fd5b505afa15801561181a573d6000803e3d6000fd5b505050506040513d602081101561183057600080fd5b505191505090565b6000805460ff1661187d576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561188f611079565b905080156118b5576118ad8160108111156118a657fe5b6027611609565b9150506118c6565b6118c2336000868661234b565b9150505b6000805460ff1916600117905592915050565b60008054819060ff16611920576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611932611079565b9050801561195d5761195081601081111561194957fe5b601e611609565b92506000915061196d9050565b6119673385612830565b92509250505b6000805460ff191660011790559092909150565b4390565b60008083831161199c5750600090508183036117b1565b506003905060006117b1565b600080836119bb575060009050806117b1565b838302838582816119c857fe5b04146119dc575060029150600090506117b1565b6000925090506117b1565b600f54604080516370a0823160e01b81526001600160a01b03858116600483015291516000939290921691839183916370a0823191602480820192602092909190829003018186803b158015611a3c57600080fd5b505afa158015611a50573d6000803e3d6000fd5b505050506040513d6020811015611a6657600080fd5b505160408051636eb1769f60e11b81526001600160a01b03888116600483015230602483015291519293506000929185169163dd62ed3e91604480820192602092909190829003018186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b50519050848210801590611afc5750848110155b9695505050505050565b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b158015611b5557600080fd5b505afa158015611b69573d6000803e3d6000fd5b505050506040513d6020811015611b7f57600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b158015611bdc57600080fd5b505af1158015611bf0573d6000803e3d6000fd5b5050505060003d60008114611c0c5760208114611c1657600080fd5b6000199150611c22565b60206000803e60005191505b5080611c75576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611cc057600080fd5b505afa158015611cd4573d6000803e3d6000fd5b505050506040513d6020811015611cea57600080fd5b5051905082811015611d43576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b158015611dbd57600080fd5b505af1158015611dd1573d6000803e3d6000fd5b505050506040513d6020811015611de757600080fd5b505190508015611e0657611dfe6003601b83612cf8565b915050610ada565b846001600160a01b0316846001600160a01b03161415611e2c57611dfe6006601c611609565b6001600160a01b0384166000908152600b602052604081205481908190611e539087611985565b90935091506000836003811115611e6657fe5b14611e8e57611e836009601a856003811115611e7e57fe5b612cf8565b945050505050610ada565b6001600160a01b0388166000908152600b6020526040902054611eb19087612d5e565b90935090506000836003811115611ec457fe5b14611edc57611e8360096019856003811115611e7e57fe5b6001600160a01b038088166000818152600b60209081526040808320879055938c168083529184902085905583518a8152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a36001600160a01b038088166000908152600c6020526040808220548b84168352912054611f6e92918216911688612139565b60055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b158015611fd957600080fd5b505af1158015611fed573d6000803e3d6000fd5b50505050611ffe888760008061234b565b5060009998505050505050505050565b6000805460ff16612053576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612065611079565b9050801561207c576118ad8160108111156118a657fe5b6118c2338560008661234b565b600061209361334c565b6000806120a886670de0b6b3a76400006119a8565b909250905060008260038111156120bb57fe5b146120da575060408051602081019091526000815290925090506117b1565b6000806120e78388612d84565b909250905060008260038111156120fa57fe5b1461211c575060408051602081019091526000815290945092506117b1915050565b604080516020810190915290815260009890975095505050505050565b816001600160a01b0316836001600160a01b03161415801561216457506000816001600160601b0316115b156122cf576001600160a01b0383161561221c576001600160a01b0383166000908152600e602052604081205463ffffffff1690816121a45760006121e3565b6001600160a01b0385166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061220a828560405180606001604052806027815260200161380160279139612daf565b905061221886848484612e59565b5050505b6001600160a01b038216156122cf576001600160a01b0382166000908152600e602052604081205463ffffffff169081612257576000612296565b6001600160a01b0384166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006122bd828560405180606001604052806026815260200161366560269139613018565b90506122cb85848484612e59565b5050505b505050565b60006122de61334c565b6000806122ef8660000151866119a8565b9092509050600082600381111561230257fe5b14612321575060408051602081019091526000815290925090506117b1565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b6000831580612358575082155b6123935760405162461bcd60e51b81526004018080602001828103825260348152602001806137aa6034913960400191505060405180910390fd5b61239b613376565b6123a361166f565b60408301819052602083018260038111156123ba57fe5b60038111156123c557fe5b90525060009050816020015160038111156123dc57fe5b146123f857611dfe6009602b83602001516003811115611e7e57fe5b841561247957606081018590526040805160208101825290820151815261241f9086611764565b608083018190526020830182600381111561243657fe5b600381111561244157fe5b905250600090508160200151600381111561245857fe5b1461247457611dfe6009602983602001516003811115611e7e57fe5b6124f2565b6124958460405180602001604052808460400151815250613082565b60608301819052602083018260038111156124ac57fe5b60038111156124b757fe5b90525060009050816020015160038111156124ce57fe5b146124ea57611dfe6009602a83602001516003811115611e7e57fe5b608081018490525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b038a8116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561255757600080fd5b505af115801561256b573d6000803e3d6000fd5b505050506040513d602081101561258157600080fd5b5051905080156125a1576125986003602883612cf8565b92505050610ada565b6125b16008548360600151611985565b60a08401819052602084018260038111156125c857fe5b60038111156125d357fe5b90525060009050826020015160038111156125ea57fe5b14612606576125986009602e84602001516003811115611e7e57fe5b6001600160a01b0387166000908152600b6020526040902054606083015161262e9190611985565b60c084018190526020840182600381111561264557fe5b600381111561265057fe5b905250600090508260200151600381111561266757fe5b14612683576125986009602d84602001516003811115611e7e57fe5b81608001516126906117b8565b10156126a257612598600e602f611609565b6126b187836080015186613099565b60a082015160085560c08201516001600160a01b0388166000818152600b60209081526040918290209390935560608501518151908152905130937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef928290030190a36080820151606080840151604080516001600160a01b038c168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a16001600160a01b038088166000908152600c6020526040812054606085015161279793919091169190612139565b60055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038c81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b15801561280457600080fd5b505af1158015612818573d6000803e3d6000fd5b5060009250612825915050565b979650505050505050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b15801561289157600080fd5b505af11580156128a5573d6000803e3d6000fd5b505050506040513d60208110156128bb57600080fd5b5051905080156128df576128d26003601f83612cf8565b9250600091506117b19050565b6128e7613376565b6128ef61166f565b604083018190526020830182600381111561290657fe5b600381111561291157fe5b905250600090508160200151600381111561292857fe5b14612952576129446009602183602001516003811115611e7e57fe5b9350600092506117b1915050565b61295c8686611b06565b60c082018190526040805160208101825290830151815261297d9190613082565b606083018190526020830182600381111561299457fe5b600381111561299f57fe5b90525060009050816020015160038111156129b657fe5b14612a08576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b612a186008548260600151612d5e565b6080830181905260208301826003811115612a2f57fe5b6003811115612a3a57fe5b9052506000905081602001516003811115612a5157fe5b14612a8d5760405162461bcd60e51b81526004018080602001828103825260288152602001806137826028913960400191505060405180910390fd5b600160601b816080015110612ad35760405162461bcd60e51b81526004018080602001828103825260238152602001806137de6023913960400191505060405180910390fd5b6001600160a01b0386166000908152600b60205260409020546060820151612afb9190612d5e565b60a0830181905260208301826003811115612b1257fe5b6003811115612b1d57fe5b9052506000905081602001516003811115612b3457fe5b14612b705760405162461bcd60e51b815260040180806020018281038252602b8152602001806136bb602b913960400191505060405180910390fd5b608081015160085560a08101516001600160a01b0387166000818152600b60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b0388169130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a36001600160a01b038087166000908152600c60205260408120546060840151612c58939190911690612139565b60055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015612cc557600080fd5b505af1158015612cd9573d6000803e3d6000fd5b5060009250612ce6915050565b8160c001519350935050509250929050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846010811115612d2757fe5b846050811115612d3357fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610ada57fe5b600080838301848110612d76576000925090506117b1565b5060029150600090506117b1565b60008082612d9857506001905060006117b1565b6000838581612da357fe5b04915091509250929050565b6000836001600160601b0316836001600160601b031611158290612e515760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e16578181015183820152602001612dfe565b50505050905090810190601f168015612e435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000612e7d4360405180606001604052806033815260200161371a60339139613290565b905060008463ffffffff16118015612ec657506001600160a01b0385166000908152600d6020908152604080832063ffffffff6000198901811685529252909120548282169116145b15612f25576001600160a01b0385166000908152600d60209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b03851602179055612fc4565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152600d83528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252600e90935292909220805460018801909316929091169190911790555b604080516001600160601b0380861682528416602082015281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000838301826001600160601b0380871690831610156130795760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e16578181015183820152602001612dfe565b50949350505050565b600080600061308f61334c565b61177b86866132ed565b600f546001600160a01b0316811561311d576010546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519183169163a9059cbb9160448082019260009290919082900301818387803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50505050613196565b806001600160a01b031663a9059cbb85856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561317d57600080fd5b505af1158015613191573d6000803e3d6000fd5b505050505b60003d80156131ac57602081146131b657600080fd5b60001991506131c2565b60206000803e60005191505b5080613215576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b8215613289576010546040805163177ead8360e11b81526001600160a01b0388811660048301526024820188905291519190921691632efd5b0691604480830192600092919082900301818387803b15801561327057600080fd5b505af1158015613284573d6000803e3d6000fd5b505050505b5050505050565b600081600160201b84106132e55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e16578181015183820152602001612dfe565b509192915050565b60006132f761334c565b60008061330c670de0b6b3a7640000876119a8565b9092509050600082600381111561331f57fe5b1461333e575060408051602081019091526000815290925090506117b1565b6117aa818660000151612089565b6040518060200160405280600081525090565b604080518082019091526000808252602082015290565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60035461010090046001600160a01b031633146134025760405162461bcd60e51b81526004018080602001828103825260248152602001806135f86024913960400191505060405180910390fd5b600754156134415760405162461bcd60e51b815260040180806020018281038252602381526020018061361c6023913960400191505060405180910390fd5b6006869055856134825760405162461bcd60e51b815260040180806020018281038252603081526020018061368b6030913960400191505060405180910390fd5b600061348d88610af1565b905080156134e2576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b83516134f590600190602087019061355f565b50825161350990600290602086019061355f565b506003805460ff191660ff8416179055613521611981565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106135a057805160ff19168380011785556135cd565b828001600101855582156135cd579182015b828111156135cd5782518255916020019190600101906135b2565b506135d99291506135dd565b5090565b61098491905b808211156135d957600081556001016135e356fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365494e563a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e6564494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f7773696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c454473616e69747920636865636b3a206e657754696d656c6f636b457363726f77206d757374207573652074686973206d61726b6574494e563a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747365786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c45446f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f4d494e545f4e45575f544f54414c5f535550504c595f4f5645525f4341504143495459494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773a265627a7a723158200fc92ea42071de51439db4ca006aaa0efd82c3c9775d952e80eb572e8cf4e0c264736f6c634300051000326080604052620d2f0060035534801561001757600080fd5b506040516107a83803806107a88339818101604052604081101561003a57600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b0319918216179091556001805493909216928116929092179055600280549091163317905561071b8061008d6000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80636f307dc3116100665780636f307dc31461013457806380f556051461013c578063ce513b6f14610144578063d215f3181461016a578063f3f43703146101905761009e565b80630fb5a6b4146100a35780631c411df3146100bd5780632efd5b06146100dc5780633ccfd60b146101085780635aa6e67514610110575b600080fd5b6100ab6101cf565b60408051918252519081900360200190f35b6100da600480360360208110156100d357600080fd5b50356101d5565b005b6100da600480360360408110156100f257600080fd5b506001600160a01b038135169060200135610223565b6100da6103e8565b610118610517565b604080516001600160a01b039092168252519081900360200190f35b610118610526565b610118610535565b6100ab6004803603602081101561015a57600080fd5b50356001600160a01b0316610544565b6100da6004803603602081101561018057600080fd5b50356001600160a01b0316610599565b6101b6600480360360208110156101a657600080fd5b50356001600160a01b0316610604565b6040805192835260208301919091528051918290030190f35b60035481565b6001546001600160a01b0316331461021e5760405162461bcd60e51b81526004018080602001828103825260278152602001806106c06027913960400191505060405180910390fd5b600355565b6002546001600160a01b0316331461027b576040805162461bcd60e51b81526020600482015260166024820152756f6e6c79206d61726b65742063616e20657363726f7760501b604482015290519081900360640190fd5b6003541561035d5761028b61067e565b506001600160a01b0382166000908152600460209081526040918290208251808401845281548152600190910154818301908152835180850190945260035442018452519092918201906102e5908563ffffffff61061d16565b90526001600160a01b0384166000818152600460209081526040918290208451815593810151600190940193909355600354815192835242019282019290925280820184905290517fdbe3ea2036231446c1c0e4706a5d2a242036540e5708cb7972a396fad591606d9181900360600190a1506103e4565b600080546040805163a9059cbb60e01b81526001600160a01b0386811660048301526024820186905291519190921692839263a9059cbb9260448083019360209383900390910190829087803b1580156103b657600080fd5b505af11580156103ca573d6000803e3d6000fd5b505050506040513d60208110156103e057600080fd5b5050505b5050565b60006103f333610544565b905060008111610440576040805162461bcd60e51b81526020600482015260136024820152724e6f7468696e6720746f20776974686472617760681b604482015290519081900360640190fd5b6000805433808352600460208181526040808620868155600101869055805163a9059cbb60e01b8152928301939093526024820186905291516001600160a01b0390931693849363a9059cbb936044808501949193918390030190829087803b1580156104ac57600080fd5b505af11580156104c0573d6000803e3d6000fd5b505050506040513d60208110156104d657600080fd5b5050604080513381526020810184905281517f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364929181900390910190a15050565b6001546001600160a01b031681565b6000546001600160a01b031681565b6002546001600160a01b031681565b600061054e61067e565b506001600160a01b0382166000908152600460209081526040918290208251808401909352805480845260019091015491830191909152421061059357806020015191505b50919050565b6001546001600160a01b031633146105e25760405162461bcd60e51b81526004018080602001828103825260278152602001806106996027913960400191505060405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6004602052600090815260409020805460019091015482565b600082820183811015610677576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60405180604001604052806000815260200160008152509056fe6f6e6c7920676f7665726e616e63652063616e2073657420697473206e657720616464726573736f6e6c7920676f7665726e616e63652063616e2073657420657363726f77206475726174696f6ea265627a7a72315820651c69ffc90968b768d73057a59c1bd68151ced3d95f1d641ff10cf25204e10d64736f6c634300051000326f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102275760003560e01c8063852a12e311610130578063b71d1a0c116100b8578063e2fdcc171161007c578063e2fdcc1714610632578063e9c714f21461063a578063f1127ed814610642578063f851a4401461069c578063fe9c44ae146106a457610227565b8063b71d1a0c14610593578063bd6d894d146105b9578063c37f68e2146105c1578063c7c934a11461060d578063db006a751461061557610227565b8063a0712d68116100ff578063a0712d681461050a578063a6afed9514610527578063aa5af0fd1461052f578063b2a02ff114610537578063b4b5ea571461056d57610227565b8063852a12e3146104c05780638aa1c05f146104dd5780638ae39cac146104fa57806395d89b411461050257610227565b80633b1d21a2116101b35780636c540baf116101825780636c540baf146104035780636f307dc31461040b5780636fcfff451461041357806370a0823114610452578063782d6fe11461047857610227565b80633b1d21a2146103a75780634576b5db146103af578063587cde1e146103d55780635fe3b567146103fb57610227565b8063182df0f5116101fa578063182df0f51461030f5780631e756d0f14610317578063267822471461033f578063313ce567146103635780633af9e6691461038157610227565b806306fdde031461022c5780630c19dc3a146102a957806317c50d06146102e157806318160ddd14610307575b600080fd5b6102346106c0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561026e578181015183820152602001610256565b50505050905090810190601f16801561029b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102cf600480360360208110156102bf57600080fd5b50356001600160a01b031661074d565b60408051918252519081900360200190f35b6102cf600480360360208110156102f757600080fd5b50356001600160a01b0316610893565b6102cf61091e565b6102cf610924565b61033d6004803603602081101561032d57600080fd5b50356001600160a01b0316610987565b005b610347610a14565b604080516001600160a01b039092168252519081900360200190f35b61036b610a23565b6040805160ff9092168252519081900360200190f35b6102cf6004803603602081101561039757600080fd5b50356001600160a01b0316610a2c565b6102cf610ae2565b6102cf600480360360208110156103c557600080fd5b50356001600160a01b0316610af1565b610347600480360360208110156103eb57600080fd5b50356001600160a01b0316610c3f565b610347610c5a565b6102cf610c69565b610347610c6f565b6104396004803603602081101561042957600080fd5b50356001600160a01b0316610c7e565b6040805163ffffffff9092168252519081900360200190f35b6102cf6004803603602081101561046857600080fd5b50356001600160a01b0316610c96565b6104a46004803603604081101561048e57600080fd5b506001600160a01b038135169060200135610cb1565b604080516001600160601b039092168252519081900360200190f35b6102cf600480360360208110156104d657600080fd5b5035610edf565b6102cf600480360360208110156104f357600080fd5b5035610eec565b6102cf610f5b565b610234610f61565b6102cf6004803603602081101561052057600080fd5b5035610fb9565b6102cf611079565b6102cf6111e9565b6102cf6004803603606081101561054d57600080fd5b506001600160a01b038135811691602081013590911690604001356111f5565b6104a46004803603602081101561058357600080fd5b50356001600160a01b0316611266565b6102cf600480360360208110156105a957600080fd5b50356001600160a01b03166112d8565b6102cf611364565b6105e7600480360360208110156105d757600080fd5b50356001600160a01b0316611420565b604080519485526020850193909352838301919091526060830152519081900360800190f35b61034761148d565b6102cf6004803603602081101561062b57600080fd5b503561149c565b6103476114a9565b6102cf6114b8565b6106746004803603604081101561065857600080fd5b5080356001600160a01b0316906020013563ffffffff166115bb565b6040805163ffffffff90931683526001600160601b0390911660208301528051918290030190f35b6103476115f0565b6106ac611604565b604080519115158252519081900360200190f35b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156107455780601f1061071a57610100808354040283529160200191610745565b820191906000526020600020905b81548152906001019060200180831161072857829003601f168201915b505050505081565b6000306001600160a01b0316826001600160a01b03166380f556056040518163ffffffff1660e01b815260040160206040518083038186803b15801561079257600080fd5b505afa1580156107a6573d6000803e3d6000fd5b505050506040513d60208110156107bc57600080fd5b50516001600160a01b0316146108035760405162461bcd60e51b81526004018080602001828103825260348152602001806136e66034913960400191505060405180910390fd5b60035461010090046001600160a01b0316331461082d576108266001603f611609565b905061088e565b601080546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f8a0324ea550ac953d4515436f05889f90a816b559ca26ee450b104d4d5a248fa929181900390910190a1505b919050565b60035460009061010090046001600160a01b031633146108b9576108266001603f611609565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f2856afeddd63e06a55f7d242638b9ce830a95d17f6ac86997a9acd7de2761628929181900390910190a150919050565b60085481565b600080600061093161166f565b9092509050600082600381111561094457fe5b146109805760405162461bcd60e51b815260040180806020018281038252603581526020018061374d6035913960400191505060405180910390fd5b9150505b90565b600f5460408051632c3e6f0f60e11b81526001600160a01b0384811660048301529151600093929092169163587cde1e91602480820192602092909190829003018186803b1580156109d857600080fd5b505afa1580156109ec573d6000803e3d6000fd5b505050506040513d6020811015610a0257600080fd5b50519050610a1082826116e4565b5050565b6004546001600160a01b031681565b60035460ff1681565b6000610a3661334c565b6040518060200160405280610a49611364565b90526001600160a01b0384166000908152600b6020526040812054919250908190610a75908490611764565b90925090506000826003811115610a8857fe5b14610ada576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610aec6117b8565b905090565b60035460009061010090046001600160a01b03163314610b17576108266001603f611609565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b158015610b5c57600080fd5b505afa158015610b70573d6000803e3d6000fd5b505050506040513d6020811015610b8657600080fd5b5051610bd9576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600c602052600090815260409020546001600160a01b031681565b6005546001600160a01b031681565b60075481565b600f546001600160a01b031681565b600e6020526000908152604090205463ffffffff1681565b6001600160a01b03166000908152600b602052604090205490565b6000438210610cf15760405162461bcd60e51b815260040180806020018281038252602681526020018061363f6026913960400191505060405180910390fd5b6001600160a01b0383166000908152600e602052604090205463ffffffff1680610d1f576000915050610ed9565b6001600160a01b0384166000908152600d6020908152604080832063ffffffff600019860181168552925290912054168310610d9b576001600160a01b0384166000908152600d602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050610ed9565b6001600160a01b0384166000908152600d6020908152604080832083805290915290205463ffffffff16831015610dd6576000915050610ed9565b600060001982015b8163ffffffff168163ffffffff161115610e9957600282820363ffffffff16048103610e0861335f565b506001600160a01b0387166000908152600d6020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b03169181019190915290871415610e7457602001519450610ed99350505050565b805163ffffffff16871115610e8b57819350610e92565b6001820392505b5050610dde565b506001600160a01b0385166000908152600d6020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b6000610ed9826001611838565b60035460009061010090046001600160a01b03163314610f12576108266001603f611609565b6009805490839055604080518281526020810185905281517f3b7a406bf2b66d0f83f6b1cf4c39edf1269cad80712b94cd80a44d13f61f1357929181900390910190a150919050565b60095481565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156107455780601f1061071a57610100808354040283529160200191610745565b600080610fc5836118d9565b50600f5460408051632c3e6f0f60e11b815233600482015290519293506000926001600160a01b039092169163587cde1e91602480820192602092909190829003018186803b15801561101757600080fd5b505afa15801561102b573d6000803e3d6000fd5b505050506040513d602081101561104157600080fd5b5051336000908152600c60205260409020549091506001600160a01b038083169116146110725761107233826116e4565b5092915050565b600080611084611981565b6007549091508082141561109d57600092505050610984565b6000806110aa8484611985565b909250905060008260038111156110bd57fe5b1461110f576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b600061111d600954836119a8565b9093509050600083600381111561113057fe5b14611182576040805162461bcd60e51b815260206004820152601a60248201527f636f756c64206e6f742063616c63756c61746520726577617264000000000000604482015290519081900360640190fd5b600060085411801561119e5750600a546001600160a01b031615155b80156111bb5750600a546111bb906001600160a01b0316826119e7565b156111d857600a546111d6906001600160a01b031682611b06565b505b600785905560009550505050505090565b670de0b6b3a764000081565b6000805460ff1661123a576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916905561125033858585611d50565b90506000805460ff191660011790559392505050565b6001600160a01b0381166000908152600e602052604081205463ffffffff1680611291576000610c38565b6001600160a01b0383166000908152600d6020908152604080832063ffffffff60001986011684529091529020546001600160601b03600160201b90910416915050919050565b60035460009061010090046001600160a01b031633146112fe5761082660016045611609565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000610c38565b6000805460ff166113a9576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556113bb611079565b14611406576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b61140e610924565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600b6020526040812054819081908190818061144961166f565b92509050600081600381111561145b57fe5b1461147757600996506000955085945084935061148692505050565b60009650919450600093509150505b9193509193565b600a546001600160a01b031681565b6000610ed982600161200e565b6010546001600160a01b031681565b6004546000906001600160a01b0316331415806114d3575033155b156114eb576114e460016000611609565b9050610984565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600d60209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b60035461010090046001600160a01b031681565b600181565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601081111561163857fe5b83605081111561164457fe5b604080519283526020830191909152600082820152519081900360600190a1826010811115610c3857fe5b60085460009081908061168a575050600654600091506116e0565b60006116946117b8565b905061169e61334c565b60006116aa8385612089565b9250905060008160038111156116bc57fe5b146116d0579450600093506116e092505050565b50516000945092506116e0915050565b9091565b6001600160a01b038083166000818152600c602081815260408084208054600b845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a461175e828483612139565b50505050565b600080600061177161334c565b61177b86866122d4565b9092509050600082600381111561178e57fe5b1461179f57509150600090506117b1565b60006117aa8261233c565b9350935050505b9250929050565b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b15801561180657600080fd5b505afa15801561181a573d6000803e3d6000fd5b505050506040513d602081101561183057600080fd5b505191505090565b6000805460ff1661187d576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561188f611079565b905080156118b5576118ad8160108111156118a657fe5b6027611609565b9150506118c6565b6118c2336000868661234b565b9150505b6000805460ff1916600117905592915050565b60008054819060ff16611920576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611932611079565b9050801561195d5761195081601081111561194957fe5b601e611609565b92506000915061196d9050565b6119673385612830565b92509250505b6000805460ff191660011790559092909150565b4390565b60008083831161199c5750600090508183036117b1565b506003905060006117b1565b600080836119bb575060009050806117b1565b838302838582816119c857fe5b04146119dc575060029150600090506117b1565b6000925090506117b1565b600f54604080516370a0823160e01b81526001600160a01b03858116600483015291516000939290921691839183916370a0823191602480820192602092909190829003018186803b158015611a3c57600080fd5b505afa158015611a50573d6000803e3d6000fd5b505050506040513d6020811015611a6657600080fd5b505160408051636eb1769f60e11b81526001600160a01b03888116600483015230602483015291519293506000929185169163dd62ed3e91604480820192602092909190829003018186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b50519050848210801590611afc5750848110155b9695505050505050565b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b158015611b5557600080fd5b505afa158015611b69573d6000803e3d6000fd5b505050506040513d6020811015611b7f57600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b158015611bdc57600080fd5b505af1158015611bf0573d6000803e3d6000fd5b5050505060003d60008114611c0c5760208114611c1657600080fd5b6000199150611c22565b60206000803e60005191505b5080611c75576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b600f54604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611cc057600080fd5b505afa158015611cd4573d6000803e3d6000fd5b505050506040513d6020811015611cea57600080fd5b5051905082811015611d43576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b158015611dbd57600080fd5b505af1158015611dd1573d6000803e3d6000fd5b505050506040513d6020811015611de757600080fd5b505190508015611e0657611dfe6003601b83612cf8565b915050610ada565b846001600160a01b0316846001600160a01b03161415611e2c57611dfe6006601c611609565b6001600160a01b0384166000908152600b602052604081205481908190611e539087611985565b90935091506000836003811115611e6657fe5b14611e8e57611e836009601a856003811115611e7e57fe5b612cf8565b945050505050610ada565b6001600160a01b0388166000908152600b6020526040902054611eb19087612d5e565b90935090506000836003811115611ec457fe5b14611edc57611e8360096019856003811115611e7e57fe5b6001600160a01b038088166000818152600b60209081526040808320879055938c168083529184902085905583518a8152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a36001600160a01b038088166000908152600c6020526040808220548b84168352912054611f6e92918216911688612139565b60055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b158015611fd957600080fd5b505af1158015611fed573d6000803e3d6000fd5b50505050611ffe888760008061234b565b5060009998505050505050505050565b6000805460ff16612053576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612065611079565b9050801561207c576118ad8160108111156118a657fe5b6118c2338560008661234b565b600061209361334c565b6000806120a886670de0b6b3a76400006119a8565b909250905060008260038111156120bb57fe5b146120da575060408051602081019091526000815290925090506117b1565b6000806120e78388612d84565b909250905060008260038111156120fa57fe5b1461211c575060408051602081019091526000815290945092506117b1915050565b604080516020810190915290815260009890975095505050505050565b816001600160a01b0316836001600160a01b03161415801561216457506000816001600160601b0316115b156122cf576001600160a01b0383161561221c576001600160a01b0383166000908152600e602052604081205463ffffffff1690816121a45760006121e3565b6001600160a01b0385166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061220a828560405180606001604052806027815260200161380160279139612daf565b905061221886848484612e59565b5050505b6001600160a01b038216156122cf576001600160a01b0382166000908152600e602052604081205463ffffffff169081612257576000612296565b6001600160a01b0384166000908152600d60209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006122bd828560405180606001604052806026815260200161366560269139613018565b90506122cb85848484612e59565b5050505b505050565b60006122de61334c565b6000806122ef8660000151866119a8565b9092509050600082600381111561230257fe5b14612321575060408051602081019091526000815290925090506117b1565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b6000831580612358575082155b6123935760405162461bcd60e51b81526004018080602001828103825260348152602001806137aa6034913960400191505060405180910390fd5b61239b613376565b6123a361166f565b60408301819052602083018260038111156123ba57fe5b60038111156123c557fe5b90525060009050816020015160038111156123dc57fe5b146123f857611dfe6009602b83602001516003811115611e7e57fe5b841561247957606081018590526040805160208101825290820151815261241f9086611764565b608083018190526020830182600381111561243657fe5b600381111561244157fe5b905250600090508160200151600381111561245857fe5b1461247457611dfe6009602983602001516003811115611e7e57fe5b6124f2565b6124958460405180602001604052808460400151815250613082565b60608301819052602083018260038111156124ac57fe5b60038111156124b757fe5b90525060009050816020015160038111156124ce57fe5b146124ea57611dfe6009602a83602001516003811115611e7e57fe5b608081018490525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b038a8116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b15801561255757600080fd5b505af115801561256b573d6000803e3d6000fd5b505050506040513d602081101561258157600080fd5b5051905080156125a1576125986003602883612cf8565b92505050610ada565b6125b16008548360600151611985565b60a08401819052602084018260038111156125c857fe5b60038111156125d357fe5b90525060009050826020015160038111156125ea57fe5b14612606576125986009602e84602001516003811115611e7e57fe5b6001600160a01b0387166000908152600b6020526040902054606083015161262e9190611985565b60c084018190526020840182600381111561264557fe5b600381111561265057fe5b905250600090508260200151600381111561266757fe5b14612683576125986009602d84602001516003811115611e7e57fe5b81608001516126906117b8565b10156126a257612598600e602f611609565b6126b187836080015186613099565b60a082015160085560c08201516001600160a01b0388166000818152600b60209081526040918290209390935560608501518151908152905130937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef928290030190a36080820151606080840151604080516001600160a01b038c168152602081019490945283810191909152517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a9299281900390910190a16001600160a01b038088166000908152600c6020526040812054606085015161279793919091169190612139565b60055460808301516060840151604080516351dff98960e01b81523060048201526001600160a01b038c81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b15801561280457600080fd5b505af1158015612818573d6000803e3d6000fd5b5060009250612825915050565b979650505050505050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b15801561289157600080fd5b505af11580156128a5573d6000803e3d6000fd5b505050506040513d60208110156128bb57600080fd5b5051905080156128df576128d26003601f83612cf8565b9250600091506117b19050565b6128e7613376565b6128ef61166f565b604083018190526020830182600381111561290657fe5b600381111561291157fe5b905250600090508160200151600381111561292857fe5b14612952576129446009602183602001516003811115611e7e57fe5b9350600092506117b1915050565b61295c8686611b06565b60c082018190526040805160208101825290830151815261297d9190613082565b606083018190526020830182600381111561299457fe5b600381111561299f57fe5b90525060009050816020015160038111156129b657fe5b14612a08576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b612a186008548260600151612d5e565b6080830181905260208301826003811115612a2f57fe5b6003811115612a3a57fe5b9052506000905081602001516003811115612a5157fe5b14612a8d5760405162461bcd60e51b81526004018080602001828103825260288152602001806137826028913960400191505060405180910390fd5b600160601b816080015110612ad35760405162461bcd60e51b81526004018080602001828103825260238152602001806137de6023913960400191505060405180910390fd5b6001600160a01b0386166000908152600b60205260409020546060820151612afb9190612d5e565b60a0830181905260208301826003811115612b1257fe5b6003811115612b1d57fe5b9052506000905081602001516003811115612b3457fe5b14612b705760405162461bcd60e51b815260040180806020018281038252602b8152602001806136bb602b913960400191505060405180910390fd5b608081015160085560a08101516001600160a01b0387166000818152600b60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b0388169130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a36001600160a01b038087166000908152600c60205260408120546060840151612c58939190911690612139565b60055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b158015612cc557600080fd5b505af1158015612cd9573d6000803e3d6000fd5b5060009250612ce6915050565b8160c001519350935050509250929050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846010811115612d2757fe5b846050811115612d3357fe5b604080519283526020830191909152818101859052519081900360600190a1836010811115610ada57fe5b600080838301848110612d76576000925090506117b1565b5060029150600090506117b1565b60008082612d9857506001905060006117b1565b6000838581612da357fe5b04915091509250929050565b6000836001600160601b0316836001600160601b031611158290612e515760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e16578181015183820152602001612dfe565b50505050905090810190601f168015612e435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000612e7d4360405180606001604052806033815260200161371a60339139613290565b905060008463ffffffff16118015612ec657506001600160a01b0385166000908152600d6020908152604080832063ffffffff6000198901811685529252909120548282169116145b15612f25576001600160a01b0385166000908152600d60209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b03851602179055612fc4565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152600d83528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252600e90935292909220805460018801909316929091169190911790555b604080516001600160601b0380861682528416602082015281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000838301826001600160601b0380871690831610156130795760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e16578181015183820152602001612dfe565b50949350505050565b600080600061308f61334c565b61177b86866132ed565b600f546001600160a01b0316811561311d576010546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519183169163a9059cbb9160448082019260009290919082900301818387803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50505050613196565b806001600160a01b031663a9059cbb85856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561317d57600080fd5b505af1158015613191573d6000803e3d6000fd5b505050505b60003d80156131ac57602081146131b657600080fd5b60001991506131c2565b60206000803e60005191505b5080613215576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b8215613289576010546040805163177ead8360e11b81526001600160a01b0388811660048301526024820188905291519190921691632efd5b0691604480830192600092919082900301818387803b15801561327057600080fd5b505af1158015613284573d6000803e3d6000fd5b505050505b5050505050565b600081600160201b84106132e55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e16578181015183820152602001612dfe565b509192915050565b60006132f761334c565b60008061330c670de0b6b3a7640000876119a8565b9092509050600082600381111561331f57fe5b1461333e575060408051602081019091526000815290925090506117b1565b6117aa818660000151612089565b6040518060200160405280600081525090565b604080518082019091526000808252602082015290565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60035461010090046001600160a01b031633146134025760405162461bcd60e51b81526004018080602001828103825260248152602001806135f86024913960400191505060405180910390fd5b600754156134415760405162461bcd60e51b815260040180806020018281038252602381526020018061361c6023913960400191505060405180910390fd5b6006869055856134825760405162461bcd60e51b815260040180806020018281038252603081526020018061368b6030913960400191505060405180910390fd5b600061348d88610af1565b905080156134e2576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b83516134f590600190602087019061355f565b50825161350990600290602086019061355f565b506003805460ff191660ff8416179055613521611981565b600755505050600992909255600a80546001600160a01b0319166001600160a01b039290921691909117905550506000805460ff1916600117905550565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106135a057805160ff19168380011785556135cd565b828001600101855582156135cd579182015b828111156135cd5782518255916020019190600101906135b2565b506135d99291506135dd565b5090565b61098491905b808211156135d957600081556001016135e356fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365494e563a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e6564494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f7773696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c454473616e69747920636865636b3a206e657754696d656c6f636b457363726f77206d757374207573652074686973206d61726b6574494e563a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747365786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c45446f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f4d494e545f4e45575f544f54414c5f535550504c595f4f5645525f4341504143495459494e563a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773a265627a7a723158200fc92ea42071de51439db4ca006aaa0efd82c3c9775d952e80eb572e8cf4e0c264736f6c63430005100032", "devdoc": { "author": "Inverse Finance", "methods": { @@ -1169,21 +1093,6 @@ "underlying_": "The address of the underlying asset" } }, - "delegate(address)": { - "params": { - "delegatee": "The address to delegate votes to" - } - }, - "delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)": { - "params": { - "delegatee": "The address to delegate votes to", - "expiry": "The time at which to expire the signature", - "nonce": "The contract state required to match the signature", - "r": "Half of the ECDSA signature pair", - "s": "Half of the ECDSA signature pair", - "v": "The recovery byte of the signature" - } - }, "exchangeRateCurrent()": { "return": "Calculated exchange rate scaled by 1e18" }, @@ -1240,6 +1149,11 @@ "seizeTokens": "The number of cTokens to seize" }, "return": "uint 0=success, otherwise a failure (see ErrorReporter.sol for details)" + }, + "syncDelegate(address)": { + "params": { + "user": "Address to sync" + } } }, "title": "xINV contract" @@ -1262,12 +1176,6 @@ "notice": "Get the underlying balance of the `owner`" }, "constructor": "Construct the xINV market", - "delegate(address)": { - "notice": "Delegate votes from `msg.sender` to `delegatee`" - }, - "delegateBySig(address,uint256,uint256,uint8,bytes32,bytes32)": { - "notice": "Delegates votes from signatory to `delegatee`" - }, "exchangeRateStored()": { "notice": "Calculates the exchange rate from the underlying to the CToken" }, @@ -1294,6 +1202,9 @@ }, "seize(address,address,uint256)": { "notice": "Transfers collateral tokens (this market) to the liquidator." + }, + "syncDelegate(address)": { + "notice": "Sync user delegate from INV" } }, "notice": "wraps INV token" @@ -1301,7 +1212,7 @@ "storageLayout": { "storage": [ { - "astId": 37347, + "astId": 37704, "contract": "contracts/XINV.sol:XINV", "label": "_notEntered", "offset": 0, @@ -1309,7 +1220,7 @@ "type": "t_bool" }, { - "astId": 37349, + "astId": 37706, "contract": "contracts/XINV.sol:XINV", "label": "name", "offset": 0, @@ -1317,7 +1228,7 @@ "type": "t_string_storage" }, { - "astId": 37351, + "astId": 37708, "contract": "contracts/XINV.sol:XINV", "label": "symbol", "offset": 0, @@ -1325,7 +1236,7 @@ "type": "t_string_storage" }, { - "astId": 37353, + "astId": 37710, "contract": "contracts/XINV.sol:XINV", "label": "decimals", "offset": 0, @@ -1333,7 +1244,7 @@ "type": "t_uint8" }, { - "astId": 37358, + "astId": 37712, "contract": "contracts/XINV.sol:XINV", "label": "admin", "offset": 1, @@ -1341,7 +1252,7 @@ "type": "t_address_payable" }, { - "astId": 37360, + "astId": 37714, "contract": "contracts/XINV.sol:XINV", "label": "pendingAdmin", "offset": 0, @@ -1349,15 +1260,15 @@ "type": "t_address_payable" }, { - "astId": 37362, + "astId": 37716, "contract": "contracts/XINV.sol:XINV", "label": "comptroller", "offset": 0, "slot": "5", - "type": "t_contract(ComptrollerInterface)30521" + "type": "t_contract(ComptrollerInterface)30383" }, { - "astId": 37364, + "astId": 37718, "contract": "contracts/XINV.sol:XINV", "label": "initialExchangeRateMantissa", "offset": 0, @@ -1365,7 +1276,7 @@ "type": "t_uint256" }, { - "astId": 37366, + "astId": 37720, "contract": "contracts/XINV.sol:XINV", "label": "accrualBlockNumber", "offset": 0, @@ -1373,7 +1284,7 @@ "type": "t_uint256" }, { - "astId": 37368, + "astId": 37722, "contract": "contracts/XINV.sol:XINV", "label": "totalSupply", "offset": 0, @@ -1381,7 +1292,7 @@ "type": "t_uint256" }, { - "astId": 37370, + "astId": 37724, "contract": "contracts/XINV.sol:XINV", "label": "rewardPerBlock", "offset": 0, @@ -1389,7 +1300,7 @@ "type": "t_uint256" }, { - "astId": 37372, + "astId": 37726, "contract": "contracts/XINV.sol:XINV", "label": "rewardTreasury", "offset": 0, @@ -1397,7 +1308,7 @@ "type": "t_address" }, { - "astId": 37376, + "astId": 37733, "contract": "contracts/XINV.sol:XINV", "label": "accountTokens", "offset": 0, @@ -1405,7 +1316,7 @@ "type": "t_mapping(t_address,t_uint256)" }, { - "astId": 38988, + "astId": 39353, "contract": "contracts/XINV.sol:XINV", "label": "delegates", "offset": 0, @@ -1413,15 +1324,15 @@ "type": "t_mapping(t_address,t_address)" }, { - "astId": 38999, + "astId": 39364, "contract": "contracts/XINV.sol:XINV", "label": "checkpoints", "offset": 0, "slot": "13", - "type": "t_mapping(t_address,t_mapping(t_uint32,t_struct(Checkpoint)38993_storage))" + "type": "t_mapping(t_address,t_mapping(t_uint32,t_struct(Checkpoint)39358_storage))" }, { - "astId": 39003, + "astId": 39368, "contract": "contracts/XINV.sol:XINV", "label": "numCheckpoints", "offset": 0, @@ -1429,28 +1340,20 @@ "type": "t_mapping(t_address,t_uint32)" }, { - "astId": 39017, - "contract": "contracts/XINV.sol:XINV", - "label": "nonces", - "offset": 0, - "slot": "15", - "type": "t_mapping(t_address,t_uint256)" - }, - { - "astId": 39841, + "astId": 40070, "contract": "contracts/XINV.sol:XINV", "label": "underlying", "offset": 0, - "slot": "16", + "slot": "15", "type": "t_address" }, { - "astId": 39843, + "astId": 40072, "contract": "contracts/XINV.sol:XINV", "label": "escrow", "offset": 0, - "slot": "17", - "type": "t_contract(TimelockEscrow)39837" + "slot": "16", + "type": "t_contract(TimelockEscrow)40066" } ], "types": { @@ -1469,12 +1372,12 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(ComptrollerInterface)30521": { + "t_contract(ComptrollerInterface)30383": { "encoding": "inplace", "label": "contract ComptrollerInterface", "numberOfBytes": "20" }, - "t_contract(TimelockEscrow)39837": { + "t_contract(TimelockEscrow)40066": { "encoding": "inplace", "label": "contract TimelockEscrow", "numberOfBytes": "20" @@ -1486,12 +1389,12 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_address,t_mapping(t_uint32,t_struct(Checkpoint)38993_storage))": { + "t_mapping(t_address,t_mapping(t_uint32,t_struct(Checkpoint)39358_storage))": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => mapping(uint32 => struct xInvCore.Checkpoint))", "numberOfBytes": "32", - "value": "t_mapping(t_uint32,t_struct(Checkpoint)38993_storage)" + "value": "t_mapping(t_uint32,t_struct(Checkpoint)39358_storage)" }, "t_mapping(t_address,t_uint256)": { "encoding": "mapping", @@ -1507,24 +1410,24 @@ "numberOfBytes": "32", "value": "t_uint32" }, - "t_mapping(t_uint32,t_struct(Checkpoint)38993_storage)": { + "t_mapping(t_uint32,t_struct(Checkpoint)39358_storage)": { "encoding": "mapping", "key": "t_uint32", "label": "mapping(uint32 => struct xInvCore.Checkpoint)", "numberOfBytes": "32", - "value": "t_struct(Checkpoint)38993_storage" + "value": "t_struct(Checkpoint)39358_storage" }, "t_string_storage": { "encoding": "bytes", "label": "string", "numberOfBytes": "32" }, - "t_struct(Checkpoint)38993_storage": { + "t_struct(Checkpoint)39358_storage": { "encoding": "inplace", "label": "struct xInvCore.Checkpoint", "members": [ { - "astId": 38990, + "astId": 39355, "contract": "contracts/XINV.sol:XINV", "label": "fromBlock", "offset": 0, @@ -1532,7 +1435,7 @@ "type": "t_uint32" }, { - "astId": 38992, + "astId": 39357, "contract": "contracts/XINV.sol:XINV", "label": "votes", "offset": 4, diff --git a/deployments/mainnet/solcInputs/f91912da5fadc7dce3430f4d2e6691b6.json b/deployments/mainnet/solcInputs/f91912da5fadc7dce3430f4d2e6691b6.json new file mode 100644 index 000000000..f0af19a9a --- /dev/null +++ b/deployments/mainnet/solcInputs/f91912da5fadc7dce3430f4d2e6691b6.json @@ -0,0 +1,182 @@ +{ + "language": "Solidity", + "sources": { + "contracts/BaseJumpRateModelV2.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\n\n/**\n * @title Logic for Compound's JumpRateModel Contract V2.\n * @author Compound (modified by Dharma Labs, refactored by Arr00)\n * @notice Version 2 modifies Version 1 by enabling updateable parameters.\n */\ncontract BaseJumpRateModelV2 {\n using SafeMath for uint;\n\n event NewInterestParams(uint baseRatePerBlock, uint multiplierPerBlock, uint jumpMultiplierPerBlock, uint kink);\n\n /**\n * @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly\n */\n address public owner;\n\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint public constant blocksPerYear = 2102400;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint public baseRatePerBlock;\n\n /**\n * @notice The multiplierPerBlock after hitting a specified utilization point\n */\n uint public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint public kink;\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly)\n */\n constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) internal {\n owner = owner_;\n\n updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock)\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function updateJumpRateModel(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) external {\n require(msg.sender == owner, \"only the owner may call this function.\");\n\n updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @return The utilization rate as a mantissa between [0, 1e18]\n */\n function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) {\n // Utilization rate is 0 when there are no borrows\n if (borrows == 0) {\n return 0;\n }\n\n return borrows.mul(1e18).div(cash.add(borrows).sub(reserves));\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRateInternal(uint cash, uint borrows, uint reserves) internal view returns (uint) {\n uint util = utilizationRate(cash, borrows, reserves);\n\n if (util <= kink) {\n return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n } else {\n uint normalRate = kink.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n uint excessUtil = util.sub(kink);\n return excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add(normalRate);\n }\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @return The supply rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) {\n uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa);\n uint borrowRate = getBorrowRateInternal(cash, borrows, reserves);\n uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);\n }\n\n /**\n * @notice Internal function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function updateJumpRateModelInternal(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) internal {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = (multiplierPerYear.mul(1e18)).div(blocksPerYear.mul(kink_));\n jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear);\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n}\n" + }, + "contracts/SafeMath.sol": { + "content": "pragma solidity ^0.5.16;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/LegacyJumpRateModelV2.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./BaseJumpRateModelV2.sol\";\nimport \"./LegacyInterestRateModel.sol\";\n\n\n/**\n * @title Compound's JumpRateModel Contract V2 for legacy cTokens\n * @author Arr00\n * @notice Supports only legacy cTokens\n */\ncontract LegacyJumpRateModelV2 is LegacyInterestRateModel, BaseJumpRateModelV2 {\n\n\t/**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @return (Error, The borrow rate percentage per block as a mantissa (scaled by 1e18))\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint, uint) {\n return (0,getBorrowRateInternal(cash, borrows, reserves));\n }\n \n constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) \n \tBaseJumpRateModelV2(baseRatePerYear,multiplierPerYear,jumpMultiplierPerYear,kink_,owner_) public {}\n}\n" + }, + "contracts/LegacyInterestRateModel.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title Compound's Legacy InterestRateModel Interface\n * @author Compound (modified by Arr00)\n */\ncontract LegacyInterestRateModel {\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\n bool public constant isInterestRateModel = true;\n\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @return error code (0 = no error), The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint,uint);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);\n\n}\n" + }, + "contracts/JumpRateModelV2.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./BaseJumpRateModelV2.sol\";\nimport \"./InterestRateModel.sol\";\n\n\n/**\n * @title Compound's JumpRateModel Contract V2 for V2 cTokens\n * @author Arr00\n * @notice Supports only for V2 cTokens\n */\ncontract JumpRateModelV2 is InterestRateModel, BaseJumpRateModelV2 {\n\n\t/**\n * @notice Calculates the current borrow rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint) {\n return getBorrowRateInternal(cash, borrows, reserves);\n }\n\n constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) \n \tBaseJumpRateModelV2(baseRatePerYear,multiplierPerYear,jumpMultiplierPerYear,kink_,owner_) public {}\n}\n" + }, + "contracts/InterestRateModel.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\ncontract InterestRateModel {\n /// @notice Indicator that this is an InterestRateModel contract (for inspection)\n bool public constant isInterestRateModel = true;\n\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);\n\n}\n" + }, + "contracts/WhitePaperInterestRateModel.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./InterestRateModel.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title Compound's WhitePaperInterestRateModel Contract\n * @author Compound\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n using SafeMath for uint;\n\n event NewInterestParams(uint baseRatePerBlock, uint multiplierPerBlock);\n\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint public constant blocksPerYear = 2102400;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint public baseRatePerBlock;\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)\n */\n constructor(uint baseRatePerYear, uint multiplierPerYear) public {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = multiplierPerYear.div(blocksPerYear);\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @return The utilization rate as a mantissa between [0, 1e18]\n */\n function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) {\n // Utilization rate is 0 when there are no borrows\n if (borrows == 0) {\n return 0;\n }\n\n return borrows.mul(1e18).div(cash.add(borrows).sub(reserves));\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) public view returns (uint) {\n uint ur = utilizationRate(cash, borrows, reserves);\n return ur.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @return The supply rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) {\n uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa);\n uint borrowRate = getBorrowRate(cash, borrows, reserves);\n uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);\n }\n}\n" + }, + "contracts/XSushiFeed.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\n\ninterface Feed {\n function decimals() external view returns (uint8);\n function latestAnswer() external view returns (uint);\n}\n\ninterface IXSushiExchangeRate {\n function getExchangeRate() external view returns (uint256);\n}\n\ncontract XSushiFeed is Feed {\n using SafeMath for uint;\n\n IXSushiExchangeRate public xSushiExchangeRate;\n Feed public sushiFeed;\n Feed public ethFeed;\n\n constructor(IXSushiExchangeRate _xSushiExchangeRate, Feed _sushiFeed, Feed _ethFeed) public {\n xSushiExchangeRate = _xSushiExchangeRate;\n sushiFeed = _sushiFeed;\n ethFeed = _ethFeed;\n }\n\n function decimals() public view returns(uint8) {\n return sushiFeed.decimals();\n }\n\n function latestAnswer() public view returns (uint) {\n uint exchangeRate = xSushiExchangeRate.getExchangeRate();\n return sushiFeed.latestAnswer()\n .mul(ethFeed.latestAnswer())\n .div(10**uint256(ethFeed.decimals()))\n .mul(exchangeRate)\n .div(10**18);\n }\n\n}" + }, + "contracts/XINV.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./EIP20Interface.sol\";\nimport \"./EIP20NonStandardInterface.sol\";\nimport \"./SafeMath.sol\";\nimport \"./Governance/IINV.sol\";\n/**\n * @title xINV Core contract\n * @notice Abstract base for xINV\n * @author Inverse Finance\n */\ncontract xInvCore is Exponential, TokenErrorReporter {\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Administrator for this contract\n */\n address payable public admin;\n\n /**\n * @notice Pending administrator for this contract\n */\n address payable public pendingAdmin;\n\n /**\n * @notice Contract which oversees inter-cToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)\n */\n uint internal initialExchangeRateMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint public accrualBlockNumber;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint public totalSupply;\n\n uint public rewardPerBlock;\n\n address public rewardTreasury;\n\n uint public constant borrowIndex = 1 ether; // for compatibility with Comptroller\n\n /**\n * @notice Official record of token balances for each account\n */\n mapping (address => uint) internal accountTokens;\n\n /**\n * @notice Indicator that this is a CToken contract (for inspection)\n */\n bool public constant isCToken = true;\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address minter, uint mintAmount, uint mintTokens);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when pendingAdmin is changed\n */\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\n\n /**\n * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\n */\n event NewAdmin(address oldAdmin, address newAdmin);\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);\n\n /**\n * @notice Event emitted when reward treasury is changed\n */\n event NewRewardTreasury(address oldRewardTreasury, address newRewardTreasury);\n\n /**\n * @notice Event emitted when reward per block is changed\n */\n event NewRewardPerBlock(uint oldRewardPerBlock, uint newRewardPerBlock);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint amount);\n\n /**\n * @notice Failure event\n */\n event Failure(uint error, uint info, uint detail);\n\n /**\n * @notice Initialize the money market\n * @param comptroller_ The address of the Comptroller\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ EIP-20 name of this token\n * @param symbol_ EIP-20 symbol of this token\n * @param decimals_ EIP-20 decimal precision of this token\n */\n function initialize(ComptrollerInterface comptroller_,\n uint initialExchangeRateMantissa_,\n uint rewardPerBlock_,\n address rewardTreasury_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_) internal {\n require(msg.sender == admin, \"only admin may initialize the market\");\n require(accrualBlockNumber == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n // Set the comptroller\n uint err = _setComptroller(comptroller_);\n require(err == uint(Error.NO_ERROR), \"setting comptroller failed\");\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n accrualBlockNumber = getBlockNumber();\n rewardPerBlock = rewardPerBlock_;\n rewardTreasury = rewardTreasury_;\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n }\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 return accountTokens[owner];\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @param owner The address of the account to query\n * @return The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external returns (uint) {\n Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});\n (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);\n require(mErr == MathError.NO_ERROR, \"balance could not be calculated\");\n return balance;\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return (possible error, token balance, borrow balance, exchange rate mantissa)\n */\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {\n uint cTokenBalance = accountTokens[account];\n uint exchangeRateMantissa;\n\n MathError mErr;\n\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\n if (mErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0, 0, 0);\n }\n\n return (uint(Error.NO_ERROR), cTokenBalance, 0, exchangeRateMantissa);\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n */\n function getBlockNumber() internal view returns (uint) {\n return block.number;\n }\n\n /**\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public nonReentrant returns (uint) {\n require(accrueInterest() == uint(Error.NO_ERROR), \"accrue interest failed\");\n return exchangeRateStored();\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() public view returns (uint) {\n (MathError err, uint result) = exchangeRateStoredInternal();\n require(err == MathError.NO_ERROR, \"exchangeRateStored: exchangeRateStoredInternal failed\");\n return result;\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the CToken\n * @return (error code, calculated exchange rate scaled by 1e18)\n */\n function exchangeRateStoredInternal() internal view returns (MathError, uint) {\n uint _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\n } else {\n /*\n * Otherwise:\n * exchangeRate = totalCash / totalSupply\n */\n uint totalCash = getCashPrior();\n Exp memory exchangeRate;\n MathError mathErr;\n\n (mathErr, exchangeRate) = getExp(totalCash, _totalSupply);\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n return (MathError.NO_ERROR, exchangeRate.mantissa);\n }\n }\n\n /**\n * @notice Get cash balance of this cToken in the underlying asset\n * @return The quantity of underlying asset owned by this contract\n */\n function getCash() external view returns (uint) {\n return getCashPrior();\n }\n\n // brings rewards from treasury into this contract\n function accrueInterest() public returns (uint) {\n /* Remember the initial block number */\n uint currentBlockNumber = getBlockNumber();\n uint accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return uint(Error.NO_ERROR);\n }\n\n /* Calculate the number of blocks elapsed since the last accrual */\n (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);\n require(mathErr == MathError.NO_ERROR, \"could not calculate block delta\");\n \n /* Calculate accumulated reward amount */\n uint reward;\n \n (mathErr, reward) = mulUInt(rewardPerBlock, blockDelta);\n require(mathErr == MathError.NO_ERROR, \"could not calculate reward\");\n\n if(totalSupply > 0 && rewardTreasury != address(0) && canTransferIn(rewardTreasury, reward)) {\n doTransferIn(rewardTreasury, reward);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n accrualBlockNumber = currentBlockNumber;\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @param mintAmount The amount of the underlying asset to supply\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\n */\n function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\n return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);\n }\n // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n return mintFresh(msg.sender, mintAmount);\n }\n\n struct MintLocalVars {\n Error err;\n MathError mathErr;\n uint exchangeRateMantissa;\n uint mintTokens;\n uint totalSupplyNew;\n uint accountTokensNew;\n uint actualMintAmount;\n }\n\n /**\n * @notice User supplies assets into the market and receives cTokens in exchange\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\n */\n function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {\n /* Fail if mint not allowed */\n uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);\n if (allowed != 0) {\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);\n }\n\n MintLocalVars memory vars;\n\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `doTransferIn` for the minter and the mintAmount.\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * `doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the cToken holds an additional `actualMintAmount`\n * of cash.\n */\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of cTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_EXCHANGE_CALCULATION_FAILED\");\n\n /*\n * We calculate the new total supply of cTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n */\n (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED\");\n require(vars.totalSupplyNew < 2**96, \"MINT_NEW_TOTAL_SUPPLY_OVER_CAPACITY\");\n\n (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED\");\n\n /* We write previously calculated values into storage */\n totalSupply = vars.totalSupplyNew;\n accountTokens[minter] = vars.accountTokensNew;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\n emit Transfer(address(this), minter, vars.mintTokens);\n\n /* we move delegates */\n _moveDelegates(address(0), delegates[minter], uint96(vars.mintTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\n\n /* We call the defense hook */\n comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);\n\n return (uint(Error.NO_ERROR), vars.actualMintAmount);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemInternal(uint redeemTokens, bool useEscrow) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\n }\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\n return redeemFresh(msg.sender, redeemTokens, 0, useEscrow);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @param redeemAmount The amount of underlying to receive from redeeming cTokens\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlyingInternal(uint redeemAmount, bool useEscrow) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\n }\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\n return redeemFresh(msg.sender, 0, redeemAmount, useEscrow);\n }\n\n struct RedeemLocalVars {\n Error err;\n MathError mathErr;\n uint exchangeRateMantissa;\n uint redeemTokens;\n uint redeemAmount;\n uint totalSupplyNew;\n uint accountTokensNew;\n }\n\n /**\n * @notice User redeems cTokens in exchange for the underlying asset\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn, bool useEscrow) internal returns (uint) {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n RedeemLocalVars memory vars;\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));\n }\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n * redeemAmount = redeemTokensIn x exchangeRateCurrent\n */\n vars.redeemTokens = redeemTokensIn;\n\n (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));\n }\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n * redeemAmount = redeemAmountIn\n */\n\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n vars.redeemAmount = redeemAmountIn;\n }\n\n /* Fail if redeem not allowed */\n uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);\n }\n\n /*\n * We calculate the new total supply and redeemer balance, checking for underflow:\n * totalSupplyNew = totalSupply - redeemTokens\n * accountTokensNew = accountTokens[redeemer] - redeemTokens\n */\n (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n /* Fail gracefully if protocol has insufficient cash */\n if (getCashPrior() < vars.redeemAmount) {\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We invoke doTransferOut for the redeemer and the redeemAmount.\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * On success, the cToken has redeemAmount less of cash.\n * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n doTransferOut(redeemer, vars.redeemAmount, useEscrow);\n\n /* We write previously calculated values into storage */\n totalSupply = vars.totalSupplyNew;\n accountTokens[redeemer] = vars.accountTokensNew;\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), vars.redeemTokens);\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\n\n /* We move delegates */\n _moveDelegates(delegates[redeemer], address(0), uint96(vars.redeemTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\n\n /* We call the defense hook */\n comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another cToken during the process of liquidation.\n * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of cTokens to seize\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.\n * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.\n * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of cTokens to seize\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {\n /* Fail if seize not allowed */\n uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);\n }\n\n MathError mathErr;\n uint borrowerTokensNew;\n uint liquidatorTokensNew;\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));\n }\n\n (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accountTokens[borrower] = borrowerTokensNew;\n accountTokens[liquidator] = liquidatorTokensNew;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, seizeTokens);\n\n /* We move delegates to liquidator although they'll be burned in the redeemFresh call after */\n _moveDelegates(delegates[borrower], delegates[liquidator], uint96(seizeTokens)); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\n\n /* We call the defense hook */\n comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);\n\n // Auto-redeem liquidator and skip escrow (cast liquidator to payable)\n redeemFresh(address(uint160(liquidator)), seizeTokens, 0, false);\n\n return uint(Error.NO_ERROR);\n }\n\n\n /*** Admin Functions ***/\n\n /**\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @param newPendingAdmin New pending admin.\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {\n // Check caller = admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);\n }\n\n // Save current value, if any, for inclusion in log\n address oldPendingAdmin = pendingAdmin;\n\n // Store pendingAdmin with value newPendingAdmin\n pendingAdmin = newPendingAdmin;\n\n // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\n * @dev Admin function for pending admin to accept role and update admin\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _acceptAdmin() external returns (uint) {\n // Check caller is pendingAdmin and pendingAdmin ≠ address(0)\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);\n }\n\n // Save current values for inclusion in log\n address oldAdmin = admin;\n address oldPendingAdmin = pendingAdmin;\n\n // Store admin with value pendingAdmin\n admin = pendingAdmin;\n\n // Clear the pending value\n pendingAdmin = address(0);\n\n emit NewAdmin(oldAdmin, admin);\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets a new comptroller for the market\n * @dev Admin function to set a new comptroller\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\n }\n\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setRewardTreasury(address newRewardTreasury) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\n }\n \n address oldRewardTreasury = rewardTreasury;\n rewardTreasury = newRewardTreasury; // it's acceptable to set it as address(0)\n\n emit NewRewardTreasury(oldRewardTreasury, newRewardTreasury);\n }\n\n function _setRewardPerBlock(uint newRewardPerBlock) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\n }\n\n uint oldRewardPerBlock = rewardPerBlock;\n rewardPerBlock = newRewardPerBlock; // it's acceptable to set it as 0\n\n emit NewRewardPerBlock(oldRewardPerBlock, newRewardPerBlock);\n\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying owned by this contract\n */\n function getCashPrior() internal view returns (uint);\n\n /**\n * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.\n * This may revert due to insufficient balance or insufficient allowance.\n */\n function doTransferIn(address from, uint amount) internal returns (uint);\n\n function canTransferIn(address from, uint amount) internal view returns (bool);\n \n /**\n * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.\n * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.\n * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.\n */\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal;\n\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n\n /*** Delegation ***/\n \n /// @notice A record of each accounts delegate\n mapping (address => address) public delegates;\n\n /// @notice A checkpoint for marking number of votes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 votes;\n }\n\n /// @notice A record of votes checkpoints for each account, by index\n mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;\n\n /// @notice The number of checkpoints for each account\n mapping (address => uint32) public numCheckpoints;\n\n /// @notice An event thats emitted when an account changes its delegate\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /// @notice An event thats emitted when a delegate account's vote balance changes\n event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);\n\n /**\n * @notice Gets the current votes balance for `account`\n * @param account The address to get votes balance\n * @return The number of current votes for `account`\n */\n function getCurrentVotes(address account) external view returns (uint96) {\n uint32 nCheckpoints = numCheckpoints[account];\n return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\n }\n\n /**\n * @notice Determine the prior number of votes for an account as of a block number\n * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\n * @param account The address of the account to check\n * @param blockNumber The block number to get the vote balance at\n * @return The number of votes the account had as of the given block\n */\n function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {\n require(blockNumber < block.number, \"INV::getPriorVotes: not yet determined\");\n\n uint32 nCheckpoints = numCheckpoints[account];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\n return checkpoints[account][nCheckpoints - 1].votes;\n }\n\n // Next check implicit zero balance\n if (checkpoints[account][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = checkpoints[account][center];\n if (cp.fromBlock == blockNumber) {\n return cp.votes;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return checkpoints[account][lower].votes;\n }\n\n function _delegate(address delegator, address delegatee) internal {\n address currentDelegate = delegates[delegator];\n uint96 delegatorBalance = uint96(accountTokens[delegator]); // NOTE: Check for potential overflows due to conversion from uint256 to uint96\n delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) {\n uint32 srcRepNum = numCheckpoints[srcRep];\n uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\n uint96 srcRepNew = sub96(srcRepOld, amount, \"INV::_moveVotes: vote amount underflows\");\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\n }\n\n if (dstRep != address(0)) {\n uint32 dstRepNum = numCheckpoints[dstRep];\n uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\n uint96 dstRepNew = add96(dstRepOld, amount, \"INV::_moveVotes: vote amount overflows\");\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\n }\n }\n }\n\n function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {\n uint32 blockNumber = safe32(block.number, \"INV::_writeCheckpoint: block number exceeds 32 bits\");\n\n if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\n } else {\n checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\n numCheckpoints[delegatee] = nCheckpoints + 1;\n }\n\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\n }\n\n function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n}\n\ncontract TimelockEscrow {\n using SafeMath for uint;\n\n address public underlying;\n address public governance;\n address public market;\n uint public duration = 10 days;\n mapping (address => EscrowData) public pendingWithdrawals;\n\n struct EscrowData {\n uint withdrawalTimestamp;\n uint amount;\n }\n\n constructor(address underlying_, address governance_) public {\n underlying = underlying_;\n governance = governance_;\n market = msg.sender;\n }\n\n // set to 0 to send funds directly to users\n function _setEscrowDuration(uint duration_) public {\n require(msg.sender == governance, \"only governance can set escrow duration\");\n duration = duration_;\n }\n\n function _setGov(address governance_) public {\n require(msg.sender == governance, \"only governance can set its new address\");\n governance = governance_;\n }\n\n /**\n * @notice assumes funds were already sent to this contract by the market. Resets escrow timelock on each withdrawal\n */\n function escrow(address user, uint amount) public {\n require(msg.sender == market, \"only market can escrow\");\n if(duration > 0) {\n EscrowData memory withdrawal = pendingWithdrawals[user];\n pendingWithdrawals[user] = EscrowData({\n // we set the future withdrawal timestamp based on current `duration` to avoid applying future `duration` changes to existing withdrawals in the event of a governance attack\n withdrawalTimestamp: block.timestamp + duration,\n amount: withdrawal.amount.add(amount)\n });\n emit Escrow(user, block.timestamp + duration, amount);\n } else { // if duration is 0, we send the funds directly to the user\n EIP20Interface token = EIP20Interface(underlying);\n token.transfer(user, amount);\n }\n }\n\n /**\n * @notice returns user withdrawable amount\n */\n function withdrawable(address user) public view returns (uint amount) {\n EscrowData memory withdrawal = pendingWithdrawals[user];\n if(withdrawal.withdrawalTimestamp <= block.timestamp) {\n amount = withdrawal.amount;\n }\n }\n\n function withdraw() public {\n uint amount = withdrawable(msg.sender);\n require(amount > 0, \"Nothing to withdraw\");\n EIP20Interface token = EIP20Interface(underlying);\n delete pendingWithdrawals[msg.sender];\n token.transfer(msg.sender, amount);\n emit Withdraw(msg.sender, amount);\n }\n\n event Escrow(address to, uint withdrawalTimestamp, uint amount);\n event Withdraw(address to, uint amount);\n}\n\n/**\n * @title xINV contract\n * @notice wraps INV token\n * @author Inverse Finance\n */\ncontract XINV is xInvCore {\n\n address public underlying;\n TimelockEscrow public escrow;\n\n /**\n * @notice Construct the xINV market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n */\n constructor(address underlying_,\n ComptrollerInterface comptroller_,\n uint rewardPerBlock_, \n address rewardTreasury_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_) public {\n // Creator of the contract is admin during initialization\n admin = msg.sender;\n\n // CToken initialize does the bulk of the work\n super.initialize(comptroller_, 1e18, rewardPerBlock_, rewardTreasury_, name_, symbol_, decimals_);\n\n // Set underlying and sanity check it\n underlying = underlying_;\n EIP20Interface(underlying).totalSupply();\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n\n // Create escrow contract\n escrow = new TimelockEscrow(underlying_, admin_);\n }\n\n /*** User Interface ***/\n\n /**\n * @notice Sync user delegate from INV\n * @param user Address to sync\n */\n function syncDelegate(address user) public {\n address invDelegate = IINV(underlying).delegates(user);\n _delegate(user, invDelegate);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @param mintAmount The amount of the underlying asset to supply\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function mint(uint mintAmount) external returns (uint) {\n (uint err,) = mintInternal(mintAmount);\n \n /* we inherit delegate from INV */\n address invDelegate = IINV(underlying).delegates(msg.sender);\n if(delegates[msg.sender] != invDelegate) {\n _delegate(msg.sender, invDelegate);\n }\n return err;\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for the underlying asset\n * @param redeemTokens The number of cTokens to redeem into underlying\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeem(uint redeemTokens) external returns (uint) {\n return redeemInternal(redeemTokens, true);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @param redeemAmount The amount of underlying to redeem\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\n return redeemUnderlyingInternal(redeemAmount, true);\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function getCashPrior() internal view returns (uint) {\n EIP20Interface token = EIP20Interface(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.\n * This will revert due to insufficient balance or insufficient allowance.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n *\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\n function doTransferIn(address from, uint amount) internal returns (uint) {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));\n token.transferFrom(from, address(this), amount);\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 { // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 { // This is a compliant ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default { // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"TOKEN_TRANSFER_IN_FAILED\");\n\n // Calculate the amount that was *actually* transferred\n uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));\n require(balanceAfter >= balanceBefore, \"TOKEN_TRANSFER_IN_OVERFLOW\");\n return balanceAfter - balanceBefore; // underflow already checked above, just subtract\n }\n\n /**\n * @dev returns true if `from` has sufficient allowance and balance to to send `amount` to this address\n */\n function canTransferIn(address from, uint amount) internal view returns (bool) {\n EIP20Interface token = EIP20Interface(underlying);\n uint balance = token.balanceOf(from);\n uint allowance = token.allowance(from, address(this));\n return balance >= amount && allowance >= amount;\n }\n\n /**\n * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory\n * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to\n * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified\n * it is >= amount, this should not revert in normal conditions.\n *\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\n function doTransferOut(address payable to, uint amount, bool useEscrow) internal {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n if(useEscrow) {\n token.transfer(address(escrow), amount);\n } else {\n token.transfer(to, amount);\n }\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 { // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 { // This is a complaint ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default { // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"TOKEN_TRANSFER_OUT_FAILED\");\n if(useEscrow) {\n escrow.escrow(to, amount);\n }\n }\n\n function _setTimelockEscrow(TimelockEscrow newTimelockEscrow) public returns (uint) {\n require(newTimelockEscrow.market() == address(this), \"sanity check: newTimelockEscrow must use this market\");\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\n }\n \n TimelockEscrow oldTimelockEscrow = escrow;\n escrow = newTimelockEscrow;\n\n emit NewTimelockEscrow(oldTimelockEscrow, newTimelockEscrow);\n }\n\n event NewTimelockEscrow(TimelockEscrow oldTimelockEscrow, TimelockEscrow newTimelockEscrow);\n}" + }, + "contracts/ComptrollerInterface.sol": { + "content": "pragma solidity ^0.5.16;\n\ncontract ComptrollerInterface {\n /// @notice Indicator that this is a Comptroller contract (for inspection)\n bool public constant isComptroller = true;\n\n /*** Assets You Are In ***/\n\n function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);\n function exitMarket(address cToken) external returns (uint);\n\n /*** Policy Hooks ***/\n\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);\n function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;\n\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;\n\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external;\n\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint);\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount,\n uint borrowerIndex) external;\n\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint);\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount,\n uint seizeTokens) external;\n\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint);\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external;\n\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external;\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address cTokenBorrowed,\n address cTokenCollateral,\n uint repayAmount) external view returns (uint, uint);\n}\n" + }, + "contracts/ErrorReporter.sol": { + "content": "pragma solidity ^0.5.16;\n\ncontract ComptrollerErrorReporter {\n enum Error {\n NO_ERROR,\n UNAUTHORIZED,\n COMPTROLLER_MISMATCH,\n INSUFFICIENT_SHORTFALL,\n INSUFFICIENT_LIQUIDITY,\n INVALID_CLOSE_FACTOR,\n INVALID_COLLATERAL_FACTOR,\n INVALID_LIQUIDATION_INCENTIVE,\n MARKET_NOT_ENTERED, // no longer possible\n MARKET_NOT_LISTED,\n MARKET_ALREADY_LISTED,\n MATH_ERROR,\n NONZERO_BORROW_BALANCE,\n PRICE_ERROR,\n REJECTION,\n SNAPSHOT_ERROR,\n TOO_MANY_ASSETS,\n TOO_MUCH_REPAY\n }\n\n enum FailureInfo {\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\n ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,\n EXIT_MARKET_BALANCE_OWED,\n EXIT_MARKET_REJECTION,\n SET_CLOSE_FACTOR_OWNER_CHECK,\n SET_CLOSE_FACTOR_VALIDATION,\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\n SET_COLLATERAL_FACTOR_NO_EXISTS,\n SET_COLLATERAL_FACTOR_VALIDATION,\n SET_COLLATERAL_FACTOR_WITHOUT_PRICE,\n SET_IMPLEMENTATION_OWNER_CHECK,\n SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,\n SET_LIQUIDATION_INCENTIVE_VALIDATION,\n SET_MAX_ASSETS_OWNER_CHECK,\n SET_PENDING_ADMIN_OWNER_CHECK,\n SET_PENDING_IMPLEMENTATION_OWNER_CHECK,\n SET_PRICE_ORACLE_OWNER_CHECK,\n SUPPORT_MARKET_EXISTS,\n SUPPORT_MARKET_OWNER_CHECK,\n SET_PAUSE_GUARDIAN_OWNER_CHECK\n }\n\n /**\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\n **/\n event Failure(uint error, uint info, uint detail);\n\n /**\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\n */\n function fail(Error err, FailureInfo info) internal returns (uint) {\n emit Failure(uint(err), uint(info), 0);\n\n return uint(err);\n }\n\n /**\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\n */\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\n emit Failure(uint(err), uint(info), opaqueError);\n\n return uint(err);\n }\n}\n\ncontract TokenErrorReporter {\n enum Error {\n NO_ERROR,\n UNAUTHORIZED,\n BAD_INPUT,\n COMPTROLLER_REJECTION,\n COMPTROLLER_CALCULATION_ERROR,\n INTEREST_RATE_MODEL_ERROR,\n INVALID_ACCOUNT_PAIR,\n INVALID_CLOSE_AMOUNT_REQUESTED,\n INVALID_COLLATERAL_FACTOR,\n MATH_ERROR,\n MARKET_NOT_FRESH,\n MARKET_NOT_LISTED,\n TOKEN_INSUFFICIENT_ALLOWANCE,\n TOKEN_INSUFFICIENT_BALANCE,\n TOKEN_INSUFFICIENT_CASH,\n TOKEN_TRANSFER_IN_FAILED,\n TOKEN_TRANSFER_OUT_FAILED\n }\n\n /*\n * Note: FailureInfo (but not Error) is kept in alphabetical order\n * This is because FailureInfo grows significantly faster, and\n * the order of Error has some meaning, while the order of FailureInfo\n * is entirely arbitrary.\n */\n enum FailureInfo {\n ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\n ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\n ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,\n ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\n ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\n ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\n ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\n BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n BORROW_ACCRUE_INTEREST_FAILED,\n BORROW_CASH_NOT_AVAILABLE,\n BORROW_FRESHNESS_CHECK,\n BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\n BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\n BORROW_MARKET_NOT_LISTED,\n BORROW_COMPTROLLER_REJECTION,\n LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,\n LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,\n LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,\n LIQUIDATE_COMPTROLLER_REJECTION,\n LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,\n LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,\n LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,\n LIQUIDATE_FRESHNESS_CHECK,\n LIQUIDATE_LIQUIDATOR_IS_BORROWER,\n LIQUIDATE_REPAY_BORROW_FRESH_FAILED,\n LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\n LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\n LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\n LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,\n LIQUIDATE_SEIZE_TOO_MUCH,\n MINT_ACCRUE_INTEREST_FAILED,\n MINT_COMPTROLLER_REJECTION,\n MINT_EXCHANGE_CALCULATION_FAILED,\n MINT_EXCHANGE_RATE_READ_FAILED,\n MINT_FRESHNESS_CHECK,\n MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\n MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\n MINT_TRANSFER_IN_FAILED,\n MINT_TRANSFER_IN_NOT_POSSIBLE,\n REDEEM_ACCRUE_INTEREST_FAILED,\n REDEEM_COMPTROLLER_REJECTION,\n REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,\n REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\n REDEEM_EXCHANGE_RATE_READ_FAILED,\n REDEEM_FRESHNESS_CHECK,\n REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\n REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\n REDEEM_TRANSFER_OUT_NOT_POSSIBLE,\n REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,\n REDUCE_RESERVES_ADMIN_CHECK,\n REDUCE_RESERVES_CASH_NOT_AVAILABLE,\n REDUCE_RESERVES_FRESH_CHECK,\n REDUCE_RESERVES_VALIDATION,\n REPAY_BEHALF_ACCRUE_INTEREST_FAILED,\n REPAY_BORROW_ACCRUE_INTEREST_FAILED,\n REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n REPAY_BORROW_COMPTROLLER_REJECTION,\n REPAY_BORROW_FRESHNESS_CHECK,\n REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\n REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\n REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,\n SET_COLLATERAL_FACTOR_OWNER_CHECK,\n SET_COLLATERAL_FACTOR_VALIDATION,\n SET_COMPTROLLER_OWNER_CHECK,\n SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,\n SET_INTEREST_RATE_MODEL_FRESH_CHECK,\n SET_INTEREST_RATE_MODEL_OWNER_CHECK,\n SET_MAX_ASSETS_OWNER_CHECK,\n SET_ORACLE_MARKET_NOT_LISTED,\n SET_PENDING_ADMIN_OWNER_CHECK,\n SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,\n SET_RESERVE_FACTOR_ADMIN_CHECK,\n SET_RESERVE_FACTOR_FRESH_CHECK,\n SET_RESERVE_FACTOR_BOUNDS_CHECK,\n TRANSFER_COMPTROLLER_REJECTION,\n TRANSFER_NOT_ALLOWED,\n TRANSFER_NOT_ENOUGH,\n TRANSFER_TOO_MUCH,\n ADD_RESERVES_ACCRUE_INTEREST_FAILED,\n ADD_RESERVES_FRESH_CHECK,\n ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE\n }\n\n /**\n * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary\n * contract-specific code that enables us to report opaque error codes from upgradeable contracts.\n **/\n event Failure(uint error, uint info, uint detail);\n\n /**\n * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator\n */\n function fail(Error err, FailureInfo info) internal returns (uint) {\n emit Failure(uint(err), uint(info), 0);\n\n return uint(err);\n }\n\n /**\n * @dev use this when reporting an opaque error from an upgradeable collaborator contract\n */\n function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {\n emit Failure(uint(err), uint(info), opaqueError);\n\n return uint(err);\n }\n}" + }, + "contracts/Exponential.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CarefulMath.sol\";\nimport \"./ExponentialNoError.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract Exponential is CarefulMath, ExponentialNoError {\n /**\n * @dev Creates an exponential from numerator and denominator values.\n * Note: Returns an error if (`num` * 10e18) > MAX_INT,\n * or if `denom` is zero.\n */\n function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {\n (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);\n if (err0 != MathError.NO_ERROR) {\n return (err0, Exp({mantissa: 0}));\n }\n\n (MathError err1, uint rational) = divUInt(scaledNumerator, denom);\n if (err1 != MathError.NO_ERROR) {\n return (err1, Exp({mantissa: 0}));\n }\n\n return (MathError.NO_ERROR, Exp({mantissa: rational}));\n }\n\n /**\n * @dev Adds two exponentials, returning a new exponential.\n */\n function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\n (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);\n\n return (error, Exp({mantissa: result}));\n }\n\n /**\n * @dev Subtracts two exponentials, returning a new exponential.\n */\n function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\n (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);\n\n return (error, Exp({mantissa: result}));\n }\n\n /**\n * @dev Multiply an Exp by a scalar, returning a new Exp.\n */\n function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\n (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);\n if (err0 != MathError.NO_ERROR) {\n return (err0, Exp({mantissa: 0}));\n }\n\n return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {\n (MathError err, Exp memory product) = mulScalar(a, scalar);\n if (err != MathError.NO_ERROR) {\n return (err, 0);\n }\n\n return (MathError.NO_ERROR, truncate(product));\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {\n (MathError err, Exp memory product) = mulScalar(a, scalar);\n if (err != MathError.NO_ERROR) {\n return (err, 0);\n }\n\n return addUInt(truncate(product), addend);\n }\n\n /**\n * @dev Divide an Exp by a scalar, returning a new Exp.\n */\n function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {\n (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);\n if (err0 != MathError.NO_ERROR) {\n return (err0, Exp({mantissa: 0}));\n }\n\n return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));\n }\n\n /**\n * @dev Divide a scalar by an Exp, returning a new Exp.\n */\n function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {\n /*\n We are doing this as:\n getExp(mulUInt(expScale, scalar), divisor.mantissa)\n\n How it works:\n Exp = a / b;\n Scalar = s;\n `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`\n */\n (MathError err0, uint numerator) = mulUInt(expScale, scalar);\n if (err0 != MathError.NO_ERROR) {\n return (err0, Exp({mantissa: 0}));\n }\n return getExp(numerator, divisor.mantissa);\n }\n\n /**\n * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.\n */\n function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {\n (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);\n if (err != MathError.NO_ERROR) {\n return (err, 0);\n }\n\n return (MathError.NO_ERROR, truncate(fraction));\n }\n\n /**\n * @dev Multiplies two exponentials, returning a new exponential.\n */\n function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\n\n (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);\n if (err0 != MathError.NO_ERROR) {\n return (err0, Exp({mantissa: 0}));\n }\n\n // We add half the scale before dividing so that we get rounding instead of truncation.\n // See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717\n // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.\n (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);\n if (err1 != MathError.NO_ERROR) {\n return (err1, Exp({mantissa: 0}));\n }\n\n (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);\n // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.\n assert(err2 == MathError.NO_ERROR);\n\n return (MathError.NO_ERROR, Exp({mantissa: product}));\n }\n\n /**\n * @dev Multiplies two exponentials given their mantissas, returning a new exponential.\n */\n function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {\n return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));\n }\n\n /**\n * @dev Multiplies three exponentials, returning a new exponential.\n */\n function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {\n (MathError err, Exp memory ab) = mulExp(a, b);\n if (err != MathError.NO_ERROR) {\n return (err, ab);\n }\n return mulExp(ab, c);\n }\n\n /**\n * @dev Divides two exponentials, returning a new exponential.\n * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,\n * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)\n */\n function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {\n return getExp(a.mantissa, b.mantissa);\n }\n}\n" + }, + "contracts/EIP20Interface.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title ERC 20 Token Standard Interface\n * https://eips.ethereum.org/EIPS/eip-20\n */\ninterface EIP20Interface {\n function name() external view returns (string memory);\n function symbol() external view returns (string memory);\n function decimals() external view returns (uint8);\n\n /**\n * @notice Get the total number of tokens in circulation\n * @return The supply of tokens\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @notice Gets the balance of the specified address\n * @param owner The address from which the balance will be retrieved\n * @return The balance\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transfer(address dst, uint256 amount) external returns (bool success);\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transferFrom(address src, address dst, uint256 amount) external returns (bool success);\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (-1 means infinite)\n * @return Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount) external returns (bool success);\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return The number of tokens allowed to be spent (-1 means infinite)\n */\n function allowance(address owner, address spender) external view returns (uint256 remaining);\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n}\n" + }, + "contracts/EIP20NonStandardInterface.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title EIP20NonStandardInterface\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ninterface EIP20NonStandardInterface {\n\n /**\n * @notice Get the total number of tokens in circulation\n * @return The supply of tokens\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @notice Gets the balance of the specified address\n * @param owner The address from which the balance will be retrieved\n * @return The balance\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n ///\n /// !!!!!!!!!!!!!!\n /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification\n /// !!!!!!!!!!!!!!\n ///\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n */\n function transfer(address dst, uint256 amount) external;\n\n ///\n /// !!!!!!!!!!!!!!\n /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification\n /// !!!!!!!!!!!!!!\n ///\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n */\n function transferFrom(address src, address dst, uint256 amount) external;\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved\n * @return Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount) external returns (bool success);\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return The number of tokens allowed to be spent\n */\n function allowance(address owner, address spender) external view returns (uint256 remaining);\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n}\n" + }, + "contracts/Governance/IINV.sol": { + "content": "pragma solidity ^0.5.16;\n\ninterface IINV {\n function balanceOf(address) external view returns (uint);\n function transfer(address,uint) external returns (bool);\n function transferFrom(address,address,uint) external returns (bool);\n function allowance(address,address) external view returns (uint);\n function delegates(address) external view returns (address);\n function delegate(address) external;\n}" + }, + "contracts/CarefulMath.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title Careful Math\n * @author Compound\n * @notice Derived from OpenZeppelin's SafeMath library\n * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol\n */\ncontract CarefulMath {\n\n /**\n * @dev Possible error codes that we can return\n */\n enum MathError {\n NO_ERROR,\n DIVISION_BY_ZERO,\n INTEGER_OVERFLOW,\n INTEGER_UNDERFLOW\n }\n\n /**\n * @dev Multiplies two numbers, returns an error on overflow.\n */\n function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {\n if (a == 0) {\n return (MathError.NO_ERROR, 0);\n }\n\n uint c = a * b;\n\n if (c / a != b) {\n return (MathError.INTEGER_OVERFLOW, 0);\n } else {\n return (MathError.NO_ERROR, c);\n }\n }\n\n /**\n * @dev Integer division of two numbers, truncating the quotient.\n */\n function divUInt(uint a, uint b) internal pure returns (MathError, uint) {\n if (b == 0) {\n return (MathError.DIVISION_BY_ZERO, 0);\n }\n\n return (MathError.NO_ERROR, a / b);\n }\n\n /**\n * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).\n */\n function subUInt(uint a, uint b) internal pure returns (MathError, uint) {\n if (b <= a) {\n return (MathError.NO_ERROR, a - b);\n } else {\n return (MathError.INTEGER_UNDERFLOW, 0);\n }\n }\n\n /**\n * @dev Adds two numbers, returns an error on overflow.\n */\n function addUInt(uint a, uint b) internal pure returns (MathError, uint) {\n uint c = a + b;\n\n if (c >= a) {\n return (MathError.NO_ERROR, c);\n } else {\n return (MathError.INTEGER_OVERFLOW, 0);\n }\n }\n\n /**\n * @dev add a and b and then subtract c\n */\n function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {\n (MathError err0, uint sum) = addUInt(a, b);\n\n if (err0 != MathError.NO_ERROR) {\n return (err0, 0);\n }\n\n return subUInt(sum, c);\n }\n}" + }, + "contracts/ExponentialNoError.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n uint constant expScale = 1e18;\n uint constant doubleScale = 1e36;\n uint constant halfExpScale = expScale/2;\n uint constant mantissaOne = expScale;\n\n struct Exp {\n uint mantissa;\n }\n\n struct Double {\n uint mantissa;\n }\n\n /**\n * @dev Truncates the given exp to a whole number value.\n * For example, truncate(Exp{mantissa: 15 * expScale}) = 15\n */\n function truncate(Exp memory exp) pure internal returns (uint) {\n // Note: We are not using careful math here as we're performing a division that cannot fail\n return exp.mantissa / expScale;\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {\n Exp memory product = mul_(a, scalar);\n return truncate(product);\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {\n Exp memory product = mul_(a, scalar);\n return add_(truncate(product), addend);\n }\n\n /**\n * @dev Checks if first Exp is less than second Exp.\n */\n function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\n return left.mantissa < right.mantissa;\n }\n\n /**\n * @dev Checks if left Exp <= right Exp.\n */\n function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {\n return left.mantissa <= right.mantissa;\n }\n\n /**\n * @dev Checks if left Exp > right Exp.\n */\n function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {\n return left.mantissa > right.mantissa;\n }\n\n /**\n * @dev returns true if Exp is exactly zero\n */\n function isZeroExp(Exp memory value) pure internal returns (bool) {\n return value.mantissa == 0;\n }\n\n function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {\n require(n < 2**224, errorMessage);\n return uint224(n);\n }\n\n function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\n return Exp({mantissa: add_(a.mantissa, b.mantissa)});\n }\n\n function add_(Double memory a, Double memory b) pure internal returns (Double memory) {\n return Double({mantissa: add_(a.mantissa, b.mantissa)});\n }\n\n function add_(uint a, uint b) pure internal returns (uint) {\n return add_(a, b, \"addition overflow\");\n }\n\n function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\n uint c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\n return Exp({mantissa: sub_(a.mantissa, b.mantissa)});\n }\n\n function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {\n return Double({mantissa: sub_(a.mantissa, b.mantissa)});\n }\n\n function sub_(uint a, uint b) pure internal returns (uint) {\n return sub_(a, b, \"subtraction underflow\");\n }\n\n function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\n return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});\n }\n\n function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {\n return Exp({mantissa: mul_(a.mantissa, b)});\n }\n\n function mul_(uint a, Exp memory b) pure internal returns (uint) {\n return mul_(a, b.mantissa) / expScale;\n }\n\n function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {\n return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});\n }\n\n function mul_(Double memory a, uint b) pure internal returns (Double memory) {\n return Double({mantissa: mul_(a.mantissa, b)});\n }\n\n function mul_(uint a, Double memory b) pure internal returns (uint) {\n return mul_(a, b.mantissa) / doubleScale;\n }\n\n function mul_(uint a, uint b) pure internal returns (uint) {\n return mul_(a, b, \"multiplication overflow\");\n }\n\n function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\n if (a == 0 || b == 0) {\n return 0;\n }\n uint c = a * b;\n require(c / a == b, errorMessage);\n return c;\n }\n\n function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {\n return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});\n }\n\n function div_(Exp memory a, uint b) pure internal returns (Exp memory) {\n return Exp({mantissa: div_(a.mantissa, b)});\n }\n\n function div_(uint a, Exp memory b) pure internal returns (uint) {\n return div_(mul_(a, expScale), b.mantissa);\n }\n\n function div_(Double memory a, Double memory b) pure internal returns (Double memory) {\n return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});\n }\n\n function div_(Double memory a, uint b) pure internal returns (Double memory) {\n return Double({mantissa: div_(a.mantissa, b)});\n }\n\n function div_(uint a, Double memory b) pure internal returns (uint) {\n return div_(mul_(a, doubleScale), b.mantissa);\n }\n\n function div_(uint a, uint b) pure internal returns (uint) {\n return div_(a, b, \"divide by zero\");\n }\n\n function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {\n require(b > 0, errorMessage);\n return a / b;\n }\n\n function fraction(uint a, uint b) pure internal returns (Double memory) {\n return Double({mantissa: div_(mul_(a, doubleScale), b)});\n }\n}\n" + }, + "contracts/Comptroller.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/IINV.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n */\ncontract Comptroller is ComptrollerV5Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError {\n /// @notice Emitted when an admin supports a market\n event MarketListed(CToken cToken);\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(CToken cToken, address account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(CToken cToken, address account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /// @notice Emitted when pause guardian is changed\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /// @notice Emitted when an action is paused globally\n event ActionPaused(string action, bool pauseState);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);\n\n /// @notice Emitted when a new COMP speed is set for a contributor\n event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);\n\n /// @notice Emitted when COMP is granted by admin\n event CompGranted(address recipient, uint amount);\n\n /// @notice The initial COMP index for a market\n uint224 public constant compInitialIndex = 1e36;\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer);\n\n return uint(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n\n uint borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint totalBorrows = CToken(cToken).totalBorrows();\n uint nextTotalBorrows = add_(totalBorrows, borrowAmount);\n require(nextTotalBorrows < borrowCap, \"market borrow cap reached\");\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n distributeBorrowerComp(cToken, borrower, borrowIndex);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n distributeBorrowerComp(cToken, borrower, borrowIndex);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower);\n distributeSupplierComp(cTokenCollateral, liquidator);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, src);\n distributeSupplierComp(cToken, dst);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToDenom;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);\n\n // sumCollateral += tokensToDenom * cTokenBalance\n vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}));\n denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {\n // Check caller is admin\n \trequire(msg.sender == admin, \"only admin can set close factor\");\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n // Note that isComped is not in active use anymore\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint i = 0; i < allMarkets.length; i ++) {\n require(allMarkets[i] != CToken(cToken), \"market already added\");\n }\n allMarkets.push(CToken(cToken));\n }\n\n\n /**\n * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing.\n * @param cTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing.\n */\n function _setMarketBorrowCaps(CToken[] calldata cTokens, uint[] calldata newBorrowCaps) external {\n \trequire(msg.sender == admin || msg.sender == borrowCapGuardian, \"only admin or borrow cap guardian can set borrow caps\"); \n\n uint numMarkets = cTokens.length;\n uint numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n for(uint i = 0; i < numMarkets; i++) {\n borrowCaps[address(cTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(cTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Admin function to change the Borrow Cap Guardian\n * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian\n */\n function _setBorrowCapGuardian(address newBorrowCapGuardian) external {\n require(msg.sender == admin, \"only admin can set borrow cap guardian\");\n\n // Save current value for inclusion in log\n address oldBorrowCapGuardian = borrowCapGuardian;\n\n // Store borrowCapGuardian with value newBorrowCapGuardian\n borrowCapGuardian = newBorrowCapGuardian;\n\n // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian)\n emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian);\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n require(unitroller._acceptImplementation() == 0, \"change not authorized\");\n }\n\n /**\n * @notice Checks caller is admin, or this contract is becoming the new implementation\n */\n function adminOrInitializing() internal view returns (bool) {\n return msg.sender == admin || msg.sender == comptrollerImplementation;\n }\n\n /*** Comp Distribution ***/\n\n /**\n * @notice Set COMP speed for a single market\n * @param cToken The market whose COMP speed to update\n * @param compSpeed New COMP speed for market\n */\n function setCompSpeedInternal(CToken cToken, uint compSpeed) internal {\n uint currentCompSpeed = compSpeeds[address(cToken)];\n if (currentCompSpeed != 0) {\n // note that COMP speed could be set to 0 to halt liquidity rewards for a market\n updateCompSupplyIndex(address(cToken));\n } else if (compSpeed != 0) {\n // Add the COMP market\n Market storage market = markets[address(cToken)];\n require(market.isListed == true, \"comp market is not listed\");\n\n if (compSupplyState[address(cToken)].index == 0 && compSupplyState[address(cToken)].block == 0) {\n compSupplyState[address(cToken)] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n }\n\n if (currentCompSpeed != compSpeed) {\n compSpeeds[address(cToken)] = compSpeed;\n emit CompSpeedUpdated(cToken, compSpeed);\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the supply index\n * @param cToken The market whose supply index to update\n */\n function updateCompSupplyIndex(address cToken) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n uint supplySpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint supplyTokens = CToken(cToken).totalSupply();\n uint compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: supplyState.index}), ratio);\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Calculate COMP accrued by a supplier and possibly transfer it to them\n * @param cToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute COMP to\n */\n function distributeSupplierComp(address cToken, address supplier) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});\n compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;\n\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {\n supplierIndex.mantissa = compInitialIndex;\n }\n\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint supplierTokens = CToken(cToken).balanceOf(supplier);\n uint supplierDelta = mul_(supplierTokens, deltaIndex);\n uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = supplierAccrued;\n emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);\n }\n\n /**\n * @notice Calculate COMP accrued by a borrower and possibly transfer it to them\n * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.\n * @param cToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute COMP to\n */\n function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);\n compAccrued[borrower] = borrowerAccrued;\n emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);\n }\n }\n\n /**\n * @notice Calculate additional accrued COMP for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint compSpeed = compContributorSpeeds[contributor];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && compSpeed > 0) {\n uint newAccrued = mul_(deltaBlocks, compSpeed);\n uint contributorAccrued = add_(compAccrued[contributor], newAccrued);\n\n compAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n }\n }\n\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) public {\n return claimComp(holder, allMarkets);\n }\n\n /**\n * @notice Claim all the comp accrued by holder in the specified markets\n * @param holder The address to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n */\n function claimComp(address holder, CToken[] memory cTokens) public {\n address[] memory holders = new address[](1);\n holders[0] = holder;\n claimComp(holders, cTokens, true, true);\n }\n\n /**\n * @notice Claim all comp accrued by the holders\n * @param holders The addresses to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n * @param borrowers Whether or not to claim COMP earned by borrowing\n * @param suppliers Whether or not to claim COMP earned by supplying\n */\n function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {\n for (uint i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"market must be listed\");\n if (borrowers == true && address(cToken) != getXinvAddress()) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n for (uint j = 0; j < holders.length; j++) {\n distributeBorrowerComp(address(cToken), holders[j], borrowIndex);\n compAccrued[holders[j]] = grantCompInternal(holders[j], compAccrued[holders[j]]);\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j]);\n compAccrued[holders[j]] = grantCompInternal(holders[j], compAccrued[holders[j]]);\n }\n }\n }\n }\n\n /**\n * @notice Transfer COMP to the user\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param amount The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function grantCompInternal(address user, uint amount) internal returns (uint) {\n IINV comp = IINV(getCompAddress());\n uint allowance = comp.allowance(getTreasuryAddress(), address(this));\n uint balance = comp.balanceOf(getTreasuryAddress());\n uint compRemaining = allowance < balance? allowance: balance; // minimum\n if (amount > 0 && amount <= compRemaining) {\n comp.transferFrom(getTreasuryAddress(), user, amount);\n return 0;\n }\n return amount;\n }\n\n /*** Comp Distribution Admin ***/\n\n /**\n * @notice Transfer COMP to the recipient\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param recipient The address of the recipient to transfer COMP to\n * @param amount The amount of COMP to (possibly) transfer\n */\n function _grantComp(address recipient, uint amount) public {\n require(adminOrInitializing(), \"only admin can grant comp\");\n uint amountLeft = grantCompInternal(recipient, amount);\n require(amountLeft == 0, \"insufficient comp for grant\");\n emit CompGranted(recipient, amount);\n }\n\n /**\n * @notice Set COMP speed for a single market\n * @param cToken The market whose COMP speed to update\n * @param compSpeed New COMP speed for market\n */\n function _setCompSpeed(CToken cToken, uint compSpeed) public {\n require(adminOrInitializing(), \"only admin can set comp speed\");\n setCompSpeedInternal(cToken, compSpeed);\n }\n\n /**\n * @notice Set COMP speed for a single contributor\n * @param contributor The contributor whose COMP speed to update\n * @param compSpeed New COMP speed for contributor\n */\n function _setContributorCompSpeed(address contributor, uint compSpeed) public {\n require(adminOrInitializing(), \"only admin can set comp speed\");\n\n // note that COMP speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (compSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n } else {\n lastContributorBlock[contributor] = getBlockNumber();\n }\n compContributorSpeeds[contributor] = compSpeed;\n\n emit ContributorCompSpeedUpdated(contributor, compSpeed);\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return The list of market addresses\n */\n function getAllMarkets() public view returns (CToken[] memory) {\n return allMarkets;\n }\n\n function getBlockNumber() public view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Return the address of the COMP token\n * @return The address of COMP\n */\n function getCompAddress() public view returns (address) {\n return 0x41D5D79431A913C4aE7d69a668ecdfE5fF9DFB68; // INV Token\n }\n\n /**\n * @notice Return the address of the Inverse treasury\n * @return The address of treasury\n */\n function getTreasuryAddress() public view returns (address) {\n return 0x926dF14a23BE491164dCF93f4c468A50ef659D5B;\n }\n\n /**\n * @notice Return the address of the xINV market\n * @return The address of xINV\n */\n function getXinvAddress() public view returns (address) {\n return 0x65b35d6Eb7006e0e607BC54EB2dFD459923476fE;\n }\n}\n" + }, + "contracts/CToken.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./CTokenInterfaces.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./EIP20Interface.sol\";\nimport \"./EIP20NonStandardInterface.sol\";\nimport \"./InterestRateModel.sol\";\n\n/**\n * @title Compound's CToken Contract\n * @notice Abstract base for CTokens\n * @author Compound\n */\ncontract CToken is CTokenInterface, Exponential, TokenErrorReporter {\n /**\n * @notice Initialize the money market\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ EIP-20 name of this token\n * @param symbol_ EIP-20 symbol of this token\n * @param decimals_ EIP-20 decimal precision of this token\n */\n function initialize(ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_) public {\n require(msg.sender == admin, \"only admin may initialize the market\");\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n // Set the comptroller\n uint err = _setComptroller(comptroller_);\n require(err == uint(Error.NO_ERROR), \"setting comptroller failed\");\n\n // Initialize block number and borrow index (block number mocks depend on comptroller being set)\n accrualBlockNumber = getBlockNumber();\n borrowIndex = mantissaOne;\n\n // Set the interest rate model (depends on block number / borrow index)\n err = _setInterestRateModelFresh(interestRateModel_);\n require(err == uint(Error.NO_ERROR), \"setting interest rate model failed\");\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n }\n\n /**\n * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n * @dev Called by both `transfer` and `transferFrom` internally\n * @param spender The address of the account performing the transfer\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param tokens The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {\n /* Fail if transfer not allowed */\n uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed);\n }\n\n /* Do not allow self-transfers */\n if (src == dst) {\n return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);\n }\n\n /* Get the allowance, infinite for the account owner */\n uint startingAllowance = 0;\n if (spender == src) {\n startingAllowance = uint(-1);\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n /* Do the calculations, checking for {under,over}flow */\n MathError mathErr;\n uint allowanceNew;\n uint srcTokensNew;\n uint dstTokensNew;\n\n (mathErr, allowanceNew) = subUInt(startingAllowance, tokens);\n if (mathErr != MathError.NO_ERROR) {\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);\n }\n\n (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens);\n if (mathErr != MathError.NO_ERROR) {\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);\n }\n\n (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);\n if (mathErr != MathError.NO_ERROR) {\n return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n accountTokens[src] = srcTokensNew;\n accountTokens[dst] = dstTokensNew;\n\n /* Eat some of the allowance (if necessary) */\n if (startingAllowance != uint(-1)) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n /* We emit a Transfer event */\n emit Transfer(src, dst, tokens);\n\n comptroller.transferVerify(address(this), src, dst, tokens);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {\n return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) {\n return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (-1 means infinite)\n * @return Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount) external returns (bool) {\n address src = msg.sender;\n transferAllowances[src][spender] = amount;\n emit Approval(src, spender, amount);\n return true;\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return The number of tokens allowed to be spent (-1 means infinite)\n */\n function allowance(address owner, address spender) external view returns (uint256) {\n return transferAllowances[owner][spender];\n }\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 return accountTokens[owner];\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external returns (uint) {\n Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});\n (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);\n require(mErr == MathError.NO_ERROR, \"balance could not be calculated\");\n return balance;\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return (possible error, token balance, borrow balance, exchange rate mantissa)\n */\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {\n uint cTokenBalance = accountTokens[account];\n uint borrowBalance;\n uint exchangeRateMantissa;\n\n MathError mErr;\n\n (mErr, borrowBalance) = borrowBalanceStoredInternal(account);\n if (mErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0, 0, 0);\n }\n\n (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();\n if (mErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0, 0, 0);\n }\n\n return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa);\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n */\n function getBlockNumber() internal view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this cToken\n * @return The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view returns (uint) {\n return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this cToken\n * @return The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view returns (uint) {\n return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return The total borrows with interest\n */\n function totalBorrowsCurrent() external nonReentrant returns (uint) {\n require(accrueInterest() == uint(Error.NO_ERROR), \"accrue interest failed\");\n return totalBorrows;\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return The calculated balance\n */\n function borrowBalanceCurrent(address account) external nonReentrant returns (uint) {\n require(accrueInterest() == uint(Error.NO_ERROR), \"accrue interest failed\");\n return borrowBalanceStored(account);\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return The calculated balance\n */\n function borrowBalanceStored(address account) public view returns (uint) {\n (MathError err, uint result) = borrowBalanceStoredInternal(account);\n require(err == MathError.NO_ERROR, \"borrowBalanceStored: borrowBalanceStoredInternal failed\");\n return result;\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return (error code, the calculated balance or 0 if error code is non-zero)\n */\n function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) {\n /* Note: we do not assert that the market is up to date */\n MathError mathErr;\n uint principalTimesIndex;\n uint result;\n\n /* Get borrowBalance and borrowIndex */\n BorrowSnapshot storage borrowSnapshot = accountBorrows[account];\n\n /* If borrowBalance = 0 then borrowIndex is likely also 0.\n * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n */\n if (borrowSnapshot.principal == 0) {\n return (MathError.NO_ERROR, 0);\n }\n\n /* Calculate new borrow balance using the interest index:\n * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n */\n (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n return (MathError.NO_ERROR, result);\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public nonReentrant returns (uint) {\n require(accrueInterest() == uint(Error.NO_ERROR), \"accrue interest failed\");\n return exchangeRateStored();\n }\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() public view returns (uint) {\n (MathError err, uint result) = exchangeRateStoredInternal();\n require(err == MathError.NO_ERROR, \"exchangeRateStored: exchangeRateStoredInternal failed\");\n return result;\n }\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 (error code, calculated exchange rate scaled by 1e18)\n */\n function exchangeRateStoredInternal() internal view returns (MathError, uint) {\n uint _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return (MathError.NO_ERROR, initialExchangeRateMantissa);\n } else {\n /*\n * Otherwise:\n * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\n */\n uint totalCash = getCashPrior();\n uint cashPlusBorrowsMinusReserves;\n Exp memory exchangeRate;\n MathError mathErr;\n\n (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);\n if (mathErr != MathError.NO_ERROR) {\n return (mathErr, 0);\n }\n\n return (MathError.NO_ERROR, exchangeRate.mantissa);\n }\n }\n\n /**\n * @notice Get cash balance of this cToken in the underlying asset\n * @return The quantity of underlying asset owned by this contract\n */\n function getCash() external view returns (uint) {\n return getCashPrior();\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n */\n function accrueInterest() public returns (uint) {\n /* Remember the initial block number */\n uint currentBlockNumber = getBlockNumber();\n uint accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return uint(Error.NO_ERROR);\n }\n\n /* Read the previous values out of storage */\n uint cashPrior = getCashPrior();\n uint borrowsPrior = totalBorrows;\n uint reservesPrior = totalReserves;\n uint borrowIndexPrior = borrowIndex;\n\n /* Calculate the current borrow interest rate */\n uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);\n require(borrowRateMantissa <= borrowRateMaxMantissa, \"borrow rate is absurdly high\");\n\n /* Calculate the number of blocks elapsed since the last accrual */\n (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);\n require(mathErr == MathError.NO_ERROR, \"could not calculate block delta\");\n\n /*\n * Calculate the interest accumulated into borrows and reserves and the new index:\n * simpleInterestFactor = borrowRate * blockDelta\n * interestAccumulated = simpleInterestFactor * totalBorrows\n * totalBorrowsNew = interestAccumulated + totalBorrows\n * totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n */\n\n Exp memory simpleInterestFactor;\n uint interestAccumulated;\n uint totalBorrowsNew;\n uint totalReservesNew;\n uint borrowIndexNew;\n\n (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));\n }\n\n (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));\n }\n\n (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));\n }\n\n (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));\n }\n\n (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n /* We emit an AccrueInterest event */\n emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\n */\n function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\n return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);\n }\n // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n return mintFresh(msg.sender, mintAmount);\n }\n\n struct MintLocalVars {\n Error err;\n MathError mathErr;\n uint exchangeRateMantissa;\n uint mintTokens;\n uint totalSupplyNew;\n uint accountTokensNew;\n uint actualMintAmount;\n }\n\n /**\n * @notice User supplies assets into the market and receives cTokens in exchange\n * @dev Assumes interest has already been accrued up to the current block\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.\n */\n function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {\n /* Fail if mint not allowed */\n uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);\n if (allowed != 0) {\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);\n }\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != getBlockNumber()) {\n return (fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), 0);\n }\n\n MintLocalVars memory vars;\n\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `doTransferIn` for the minter and the mintAmount.\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * `doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the cToken holds an additional `actualMintAmount`\n * of cash.\n */\n vars.actualMintAmount = doTransferIn(minter, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of cTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_EXCHANGE_CALCULATION_FAILED\");\n\n /*\n * We calculate the new total supply of cTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n */\n (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED\");\n\n (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);\n require(vars.mathErr == MathError.NO_ERROR, \"MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED\");\n\n /* We write previously calculated values into storage */\n totalSupply = vars.totalSupplyNew;\n accountTokens[minter] = vars.accountTokensNew;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, vars.actualMintAmount, vars.mintTokens);\n emit Transfer(address(this), minter, vars.mintTokens);\n\n /* We call the defense hook */\n comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);\n\n return (uint(Error.NO_ERROR), vars.actualMintAmount);\n }\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 a failure (see ErrorReporter.sol for details)\n */\n function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\n }\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\n return redeemFresh(msg.sender, redeemTokens, 0);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to receive from redeeming cTokens\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed\n return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);\n }\n // redeemFresh emits redeem-specific logs on errors, so we don't need to\n return redeemFresh(msg.sender, 0, redeemAmount);\n }\n\n struct RedeemLocalVars {\n Error err;\n MathError mathErr;\n uint exchangeRateMantissa;\n uint redeemTokens;\n uint redeemAmount;\n uint totalSupplyNew;\n uint accountTokensNew;\n }\n\n /**\n * @notice User redeems cTokens in exchange for the underlying asset\n * @dev Assumes interest has already been accrued up to the current block\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n RedeemLocalVars memory vars;\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));\n }\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n * redeemAmount = redeemTokensIn x exchangeRateCurrent\n */\n vars.redeemTokens = redeemTokensIn;\n\n (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));\n }\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n * redeemAmount = redeemAmountIn\n */\n\n (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n vars.redeemAmount = redeemAmountIn;\n }\n\n /* Fail if redeem not allowed */\n uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);\n }\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != getBlockNumber()) {\n return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK);\n }\n\n /*\n * We calculate the new total supply and redeemer balance, checking for underflow:\n * totalSupplyNew = totalSupply - redeemTokens\n * accountTokensNew = accountTokens[redeemer] - redeemTokens\n */\n (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n /* Fail gracefully if protocol has insufficient cash */\n if (getCashPrior() < vars.redeemAmount) {\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We invoke doTransferOut for the redeemer and the redeemAmount.\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * On success, the cToken has redeemAmount less of cash.\n * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n doTransferOut(redeemer, vars.redeemAmount);\n\n /* We write previously calculated values into storage */\n totalSupply = vars.totalSupplyNew;\n accountTokens[redeemer] = vars.accountTokensNew;\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), vars.redeemTokens);\n emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);\n\n /* We call the defense hook */\n comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\n return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);\n }\n // borrowFresh emits borrow-specific logs on errors, so we don't need to\n return borrowFresh(msg.sender, borrowAmount);\n }\n\n struct BorrowLocalVars {\n MathError mathErr;\n uint accountBorrows;\n uint accountBorrowsNew;\n uint totalBorrowsNew;\n }\n\n /**\n * @notice Users borrow assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {\n /* Fail if borrow not allowed */\n uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);\n }\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != getBlockNumber()) {\n return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);\n }\n\n /* Fail gracefully if protocol has insufficient underlying cash */\n if (getCashPrior() < borrowAmount) {\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);\n }\n\n BorrowLocalVars memory vars;\n\n /*\n * We calculate the new borrower and total borrow balances, failing on overflow:\n * accountBorrowsNew = accountBorrows + borrowAmount\n * totalBorrowsNew = totalBorrows + borrowAmount\n */\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount);\n if (vars.mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We invoke doTransferOut for the borrower and the borrowAmount.\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * On success, the cToken borrowAmount less of cash.\n * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n doTransferOut(borrower, borrowAmount);\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = vars.totalBorrowsNew;\n\n /* We emit a Borrow event */\n emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);\n\n /* We call the defense hook */\n comptroller.borrowVerify(address(this), borrower, borrowAmount);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.\n */\n function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint, uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\n return (fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED), 0);\n }\n // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n return repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.\n */\n function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint, uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed\n return (fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED), 0);\n }\n // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n return repayBorrowFresh(msg.sender, borrower, repayAmount);\n }\n\n struct RepayBorrowLocalVars {\n Error err;\n MathError mathErr;\n uint repayAmount;\n uint borrowerIndex;\n uint accountBorrows;\n uint accountBorrowsNew;\n uint totalBorrowsNew;\n uint actualRepayAmount;\n }\n\n /**\n * @notice Borrows are repaid by another user (possibly the borrower).\n * @param payer the account paying off the borrow\n * @param borrower the account with the debt being payed off\n * @param repayAmount the amount of undelrying tokens being returned\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.\n */\n function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {\n /* Fail if repayBorrow not allowed */\n uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);\n if (allowed != 0) {\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed), 0);\n }\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != getBlockNumber()) {\n return (fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK), 0);\n }\n\n RepayBorrowLocalVars memory vars;\n\n /* We remember the original borrowerIndex for verification purposes */\n vars.borrowerIndex = accountBorrows[borrower].interestIndex;\n\n /* We fetch the amount the borrower owes, with accumulated interest */\n (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);\n if (vars.mathErr != MathError.NO_ERROR) {\n return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);\n }\n\n /* If repayAmount == -1, repayAmount = accountBorrows */\n if (repayAmount == uint(-1)) {\n vars.repayAmount = vars.accountBorrows;\n } else {\n vars.repayAmount = repayAmount;\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call doTransferIn for the payer and the repayAmount\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * On success, the cToken holds an additional repayAmount of cash.\n * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);\n\n /*\n * We calculate the new borrower and total borrow balances, failing on underflow:\n * accountBorrowsNew = accountBorrows - actualRepayAmount\n * totalBorrowsNew = totalBorrows - actualRepayAmount\n */\n (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);\n require(vars.mathErr == MathError.NO_ERROR, \"REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED\");\n\n (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);\n require(vars.mathErr == MathError.NO_ERROR, \"REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED\");\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = vars.accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = vars.totalBorrowsNew;\n\n /* We emit a RepayBorrow event */\n emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);\n\n /* We call the defense hook */\n comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex);\n\n return (uint(Error.NO_ERROR), vars.actualRepayAmount);\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this cToken to be liquidated\n * @param cTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.\n */\n function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant returns (uint, uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED), 0);\n }\n\n error = cTokenCollateral.accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED), 0);\n }\n\n // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n return liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);\n }\n\n /**\n * @notice The liquidator liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this cToken to be liquidated\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param cTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.\n */\n function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal returns (uint, uint) {\n /* Fail if liquidate not allowed */\n uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);\n if (allowed != 0) {\n return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed), 0);\n }\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != getBlockNumber()) {\n return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK), 0);\n }\n\n /* Verify cTokenCollateral market's block number equals current block number */\n if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {\n return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK), 0);\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n return (fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER), 0);\n }\n\n /* Fail if repayAmount = 0 */\n if (repayAmount == 0) {\n return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO), 0);\n }\n\n /* Fail if repayAmount = -1 */\n if (repayAmount == uint(-1)) {\n return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX), 0);\n }\n\n\n /* Fail if repayBorrow fails */\n (uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh(liquidator, borrower, repayAmount);\n if (repayBorrowError != uint(Error.NO_ERROR)) {\n return (fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED), 0);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We calculate the number of collateral tokens that will be seized */\n (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount);\n require(amountSeizeError == uint(Error.NO_ERROR), \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n /* Revert if borrower collateral token balance < seizeTokens */\n require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call\n uint seizeError;\n if (address(cTokenCollateral) == address(this)) {\n seizeError = seizeInternal(address(this), liquidator, borrower, seizeTokens);\n } else {\n seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens);\n }\n\n /* Revert if seize tokens fails (since we cannot be sure of side effects) */\n require(seizeError == uint(Error.NO_ERROR), \"token seizure failed\");\n\n /* We emit a LiquidateBorrow event */\n emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);\n\n /* We call the defense hook */\n comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens);\n\n return (uint(Error.NO_ERROR), actualRepayAmount);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another cToken during the process of liquidation.\n * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of cTokens to seize\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {\n return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.\n * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.\n * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of cTokens to seize\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {\n /* Fail if seize not allowed */\n uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);\n if (allowed != 0) {\n return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);\n }\n\n MathError mathErr;\n uint borrowerTokensNew;\n uint liquidatorTokensNew;\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));\n }\n\n (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);\n if (mathErr != MathError.NO_ERROR) {\n return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accountTokens[borrower] = borrowerTokensNew;\n accountTokens[liquidator] = liquidatorTokensNew;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, seizeTokens);\n\n /* We call the defense hook */\n comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);\n\n return uint(Error.NO_ERROR);\n }\n\n\n /*** Admin Functions ***/\n\n /**\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @param newPendingAdmin New pending admin.\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {\n // Check caller = admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);\n }\n\n // Save current value, if any, for inclusion in log\n address oldPendingAdmin = pendingAdmin;\n\n // Store pendingAdmin with value newPendingAdmin\n pendingAdmin = newPendingAdmin;\n\n // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\n * @dev Admin function for pending admin to accept role and update admin\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _acceptAdmin() external returns (uint) {\n // Check caller is pendingAdmin and pendingAdmin ≠ address(0)\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);\n }\n\n // Save current values for inclusion in log\n address oldAdmin = admin;\n address oldPendingAdmin = pendingAdmin;\n\n // Store admin with value pendingAdmin\n admin = pendingAdmin;\n\n // Clear the pending value\n pendingAdmin = address(0);\n\n emit NewAdmin(oldAdmin, admin);\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets a new comptroller for the market\n * @dev Admin function to set a new comptroller\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);\n }\n\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.\n return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED);\n }\n // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.\n return _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n /**\n * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n * @dev Admin function to set a new reserve factor\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK);\n }\n\n // Verify market's block number equals current block number\n if (accrualBlockNumber != getBlockNumber()) {\n return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);\n }\n\n // Check newReserveFactor ≤ maxReserveFactor\n if (newReserveFactorMantissa > reserveFactorMaxMantissa) {\n return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);\n }\n\n uint oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring from msg.sender\n * @param addAmount Amount of addition to reserves\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.\n return fail(Error(error), FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED);\n }\n\n // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to.\n (error, ) = _addReservesFresh(addAmount);\n return error;\n }\n\n /**\n * @notice Add reserves by transferring from caller\n * @dev Requires fresh interest accrual\n * @param addAmount Amount of addition to reserves\n * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees\n */\n function _addReservesFresh(uint addAmount) internal returns (uint, uint) {\n // totalReserves + actualAddAmount\n uint totalReservesNew;\n uint actualAddAmount;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != getBlockNumber()) {\n return (fail(Error.MARKET_NOT_FRESH, FailureInfo.ADD_RESERVES_FRESH_CHECK), actualAddAmount);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call doTransferIn for the caller and the addAmount\n * Note: The cToken must handle variations between ERC-20 and ETH underlying.\n * On success, the cToken holds an additional addAmount of cash.\n * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n\n actualAddAmount = doTransferIn(msg.sender, addAmount);\n\n totalReservesNew = totalReserves + actualAddAmount;\n\n /* Revert on overflow */\n require(totalReservesNew >= totalReserves, \"add reserves unexpected overflow\");\n\n // Store reserves[n+1] = reserves[n] + actualAddAmount\n totalReserves = totalReservesNew;\n\n /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n /* Return (NO_ERROR, actualAddAmount) */\n return (uint(Error.NO_ERROR), actualAddAmount);\n }\n\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to admin\n * @param reduceAmount Amount of reduction to reserves\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.\n return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED);\n }\n // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.\n return _reduceReservesFresh(reduceAmount);\n }\n\n /**\n * @notice Reduces reserves by transferring to admin\n * @dev Requires fresh interest accrual\n * @param reduceAmount Amount of reduction to reserves\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {\n // totalReserves - reduceAmount\n uint totalReservesNew;\n\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK);\n }\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != getBlockNumber()) {\n return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);\n }\n\n // Fail gracefully if protocol has insufficient underlying cash\n if (getCashPrior() < reduceAmount) {\n return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE);\n }\n\n // Check reduceAmount ≤ reserves[n] (totalReserves)\n if (reduceAmount > totalReserves) {\n return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n totalReservesNew = totalReserves - reduceAmount;\n // We checked reduceAmount <= totalReserves above, so this should never revert.\n require(totalReservesNew <= totalReserves, \"reduce reserves unexpected underflow\");\n\n // Store reserves[n+1] = reserves[n] - reduceAmount\n totalReserves = totalReservesNew;\n\n // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n doTransferOut(admin, reduceAmount);\n\n emit ReservesReduced(admin, reduceAmount, totalReservesNew);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {\n uint error = accrueInterest();\n if (error != uint(Error.NO_ERROR)) {\n // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed\n return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED);\n }\n // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.\n return _setInterestRateModelFresh(newInterestRateModel);\n }\n\n /**\n * @notice updates the interest rate model (*requires fresh interest accrual)\n * @dev Admin function to update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {\n\n // Used to store old model for use in the event that is emitted on success\n InterestRateModel oldInterestRateModel;\n\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK);\n }\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != getBlockNumber()) {\n return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);\n }\n\n // Track the market's current interest rate model\n oldInterestRateModel = interestRateModel;\n\n // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n // Set the interest rate model to newInterestRateModel\n interestRateModel = newInterestRateModel;\n\n // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying owned by this contract\n */\n function getCashPrior() internal view returns (uint);\n\n /**\n * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.\n * This may revert due to insufficient balance or insufficient allowance.\n */\n function doTransferIn(address from, uint amount) internal returns (uint);\n\n /**\n * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.\n * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.\n * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.\n */\n function doTransferOut(address payable to, uint amount) internal;\n\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n}\n" + }, + "contracts/PriceOracle.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\n\ncontract PriceOracle {\n /// @notice Indicator that this is a PriceOracle contract (for inspection)\n bool public constant isPriceOracle = true;\n\n /**\n * @notice Get the underlying price of a cToken asset\n * @param cToken The cToken to get the underlying price of\n * @return The underlying asset price mantissa (scaled by 1e18).\n * Zero means the price is unavailable.\n */\n function getUnderlyingPrice(CToken cToken) external view returns (uint);\n}\n" + }, + "contracts/ComptrollerStorage.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./PriceOracle.sol\";\n\ncontract UnitrollerAdminStorage {\n /**\n * @notice Administrator for this contract\n */\n address public admin;\n\n /**\n * @notice Pending administrator for this contract\n */\n address public pendingAdmin;\n\n /**\n * @notice Active brains of Unitroller\n */\n address public comptrollerImplementation;\n\n /**\n * @notice Pending brains of Unitroller\n */\n address public pendingComptrollerImplementation;\n}\n\ncontract ComptrollerV1Storage is UnitrollerAdminStorage {\n\n /**\n * @notice Oracle which gives the price of any given asset\n */\n PriceOracle public oracle;\n\n /**\n * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n */\n uint public closeFactorMantissa;\n\n /**\n * @notice Multiplier representing the discount on collateral that a liquidator receives\n */\n uint public liquidationIncentiveMantissa;\n\n /**\n * @notice Max number of assets a single account can participate in (borrow or use as collateral)\n */\n uint public maxAssets;\n\n /**\n * @notice Per-account mapping of \"assets you are in\", capped by maxAssets\n */\n mapping(address => CToken[]) public accountAssets;\n\n}\n\ncontract ComptrollerV2Storage is ComptrollerV1Storage {\n struct Market {\n /// @notice Whether or not this market is listed\n bool isListed;\n\n /**\n * @notice Multiplier representing the most one can borrow against their collateral in this market.\n * For instance, 0.9 to allow borrowing 90% of collateral value.\n * Must be between 0 and 1, and stored as a mantissa.\n */\n uint collateralFactorMantissa;\n\n /// @notice Per-market mapping of \"accounts in this asset\"\n mapping(address => bool) accountMembership;\n\n /// @notice Whether or not this market receives COMP\n bool isComped;\n }\n\n /**\n * @notice Official mapping of cTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n\n /**\n * @notice The Pause Guardian can pause certain actions as a safety mechanism.\n * Actions which allow users to remove their own assets cannot be paused.\n * Liquidation / seizing / transfer can only be paused globally, not by market.\n */\n address public pauseGuardian;\n bool public _mintGuardianPaused;\n bool public _borrowGuardianPaused;\n bool public transferGuardianPaused;\n bool public seizeGuardianPaused;\n mapping(address => bool) public mintGuardianPaused;\n mapping(address => bool) public borrowGuardianPaused;\n}\n\ncontract ComptrollerV3Storage is ComptrollerV2Storage {\n struct CompMarketState {\n /// @notice The market's last updated compBorrowIndex or compSupplyIndex\n uint224 index;\n\n /// @notice The block number the index was last updated at\n uint32 block;\n }\n\n /// @notice A list of all markets\n CToken[] public allMarkets;\n\n /// @notice The rate at which the flywheel distributes COMP, per block\n uint public compRate;\n\n /// @notice The portion of compRate that each market currently receives\n mapping(address => uint) public compSpeeds;\n\n /// @notice The COMP market supply state for each market\n mapping(address => CompMarketState) public compSupplyState;\n\n /// @notice The COMP market borrow state for each market\n mapping(address => CompMarketState) public compBorrowState;\n\n /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP\n mapping(address => mapping(address => uint)) public compSupplierIndex;\n\n /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP\n mapping(address => mapping(address => uint)) public compBorrowerIndex;\n\n /// @notice The COMP accrued but not yet transferred to each user\n mapping(address => uint) public compAccrued;\n}\n\ncontract ComptrollerV4Storage is ComptrollerV3Storage {\n // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market.\n address public borrowCapGuardian;\n\n // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing.\n mapping(address => uint) public borrowCaps;\n}\n\ncontract ComptrollerV5Storage is ComptrollerV4Storage {\n /// @notice The portion of COMP that each contributor receives per block\n mapping(address => uint) public compContributorSpeeds;\n\n /// @notice Last block at which a contributor's COMP rewards have been allocated\n mapping(address => uint) public lastContributorBlock;\n}\n" + }, + "contracts/Unitroller.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./ErrorReporter.sol\";\nimport \"./ComptrollerStorage.sol\";\n/**\n * @title ComptrollerCore\n * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`.\n * CTokens should reference this contract as their comptroller.\n */\ncontract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter {\n\n /**\n * @notice Emitted when pendingComptrollerImplementation is changed\n */\n event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation);\n\n /**\n * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated\n */\n event NewImplementation(address oldImplementation, address newImplementation);\n\n /**\n * @notice Emitted when pendingAdmin is changed\n */\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\n\n /**\n * @notice Emitted when pendingAdmin is accepted, which means admin is updated\n */\n event NewAdmin(address oldAdmin, address newAdmin);\n\n constructor() public {\n // Set admin to caller\n admin = msg.sender;\n }\n\n /*** Admin Functions ***/\n function _setPendingImplementation(address newPendingImplementation) public returns (uint) {\n\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK);\n }\n\n address oldPendingImplementation = pendingComptrollerImplementation;\n\n pendingComptrollerImplementation = newPendingImplementation;\n\n emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation\n * @dev Admin function for new implementation to accept it's role as implementation\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _acceptImplementation() public returns (uint) {\n // Check caller is pendingImplementation and pendingImplementation ≠ address(0)\n if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) {\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK);\n }\n\n // Save current values for inclusion in log\n address oldImplementation = comptrollerImplementation;\n address oldPendingImplementation = pendingComptrollerImplementation;\n\n comptrollerImplementation = pendingComptrollerImplementation;\n\n pendingComptrollerImplementation = address(0);\n\n emit NewImplementation(oldImplementation, comptrollerImplementation);\n emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);\n\n return uint(Error.NO_ERROR);\n }\n\n\n /**\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @param newPendingAdmin New pending admin.\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPendingAdmin(address newPendingAdmin) public returns (uint) {\n // Check caller = admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);\n }\n\n // Save current value, if any, for inclusion in log\n address oldPendingAdmin = pendingAdmin;\n\n // Store pendingAdmin with value newPendingAdmin\n pendingAdmin = newPendingAdmin;\n\n // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)\n emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\n * @dev Admin function for pending admin to accept role and update admin\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _acceptAdmin() public returns (uint) {\n // Check caller is pendingAdmin and pendingAdmin ≠ address(0)\n if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);\n }\n\n // Save current values for inclusion in log\n address oldAdmin = admin;\n address oldPendingAdmin = pendingAdmin;\n\n // Store admin with value pendingAdmin\n admin = pendingAdmin;\n\n // Clear the pending value\n pendingAdmin = address(0);\n\n emit NewAdmin(oldAdmin, admin);\n emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @dev Delegates execution to an implementation contract.\n * It returns to the external caller whatever the implementation returns\n * or forwards reverts.\n */\n function () payable external {\n // delegate all other functions to current implementation\n (bool success, ) = comptrollerImplementation.delegatecall(msg.data);\n\n assembly {\n let free_mem_ptr := mload(0x40)\n returndatacopy(free_mem_ptr, 0, returndatasize)\n\n switch success\n case 0 { revert(free_mem_ptr, returndatasize) }\n default { return(free_mem_ptr, returndatasize) }\n }\n }\n}\n" + }, + "contracts/CTokenInterfaces.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./InterestRateModel.sol\";\n\ncontract CTokenStorage {\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Maximum borrow rate that can ever be applied (.0005% / block)\n */\n\n uint internal constant borrowRateMaxMantissa = 0.0005e16;\n\n /**\n * @notice Maximum fraction of interest that can be set aside for reserves\n */\n uint internal constant reserveFactorMaxMantissa = 1e18;\n\n /**\n * @notice Administrator for this contract\n */\n address payable public admin;\n\n /**\n * @notice Pending administrator for this contract\n */\n address payable public pendingAdmin;\n\n /**\n * @notice Contract which oversees inter-cToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Model which tells what the current interest rate should be\n */\n InterestRateModel public interestRateModel;\n\n /**\n * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)\n */\n uint internal initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint public totalSupply;\n\n /**\n * @notice Official record of token balances for each account\n */\n mapping (address => uint) internal accountTokens;\n\n /**\n * @notice Approved token transfer amounts on behalf of others\n */\n mapping (address => mapping (address => uint)) internal transferAllowances;\n\n /**\n * @notice Container for borrow balance information\n * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n */\n struct BorrowSnapshot {\n uint principal;\n uint interestIndex;\n }\n\n /**\n * @notice Mapping of account addresses to outstanding borrow balances\n */\n mapping(address => BorrowSnapshot) internal accountBorrows;\n}\n\ncontract CTokenInterface is CTokenStorage {\n /**\n * @notice Indicator that this is a CToken contract (for inspection)\n */\n bool public constant isCToken = true;\n\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address minter, uint mintAmount, uint mintTokens);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);\n\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when pendingAdmin is changed\n */\n event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\n\n /**\n * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\n */\n event NewAdmin(address oldAdmin, address newAdmin);\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint amount);\n\n /**\n * @notice Failure event\n */\n event Failure(uint error, uint info, uint detail);\n\n\n /*** User Interface ***/\n\n function transfer(address dst, uint amount) external returns (bool);\n function transferFrom(address src, address dst, uint amount) external returns (bool);\n function approve(address spender, uint amount) external returns (bool);\n function allowance(address owner, address spender) external view returns (uint);\n function balanceOf(address owner) external view returns (uint);\n function balanceOfUnderlying(address owner) external returns (uint);\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint);\n function borrowRatePerBlock() external view returns (uint);\n function supplyRatePerBlock() external view returns (uint);\n function totalBorrowsCurrent() external returns (uint);\n function borrowBalanceCurrent(address account) external returns (uint);\n function borrowBalanceStored(address account) public view returns (uint);\n function exchangeRateCurrent() public returns (uint);\n function exchangeRateStored() public view returns (uint);\n function getCash() external view returns (uint);\n function accrueInterest() public returns (uint);\n function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint);\n\n\n /*** Admin Functions ***/\n\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint);\n function _acceptAdmin() external returns (uint);\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint);\n function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);\n function _reduceReserves(uint reduceAmount) external returns (uint);\n function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint);\n}\n\ncontract CErc20Storage {\n /**\n * @notice Underlying asset for this CToken\n */\n address public underlying;\n}\n\ncontract CErc20Interface is CErc20Storage {\n\n /*** User Interface ***/\n\n function mint(uint mintAmount) external returns (uint);\n function redeem(uint redeemTokens) external returns (uint);\n function redeemUnderlying(uint redeemAmount) external returns (uint);\n function borrow(uint borrowAmount) external returns (uint);\n function repayBorrow(uint repayAmount) external returns (uint);\n function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);\n function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint);\n\n\n /*** Admin Functions ***/\n\n function _addReserves(uint addAmount) external returns (uint);\n}\n\ncontract CDelegationStorage {\n /**\n * @notice Implementation address for this contract\n */\n address public implementation;\n}\n\ncontract CDelegatorInterface is CDelegationStorage {\n /**\n * @notice Emitted when implementation is changed\n */\n event NewImplementation(address oldImplementation, address newImplementation);\n\n /**\n * @notice Called by the admin to update the implementation of the delegator\n * @param implementation_ The address of the new implementation for delegation\n * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation\n * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation\n */\n function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public;\n}\n\ncontract CDelegateInterface is CDelegationStorage {\n /**\n * @notice Called by the delegator on a delegate to initialize it for duty\n * @dev Should revert if any issues arise which make it unfit for delegation\n * @param data The encoded bytes data for any initialization\n */\n function _becomeImplementation(bytes memory data) public;\n\n /**\n * @notice Called by the delegator on a delegate to forfeit its responsibility\n */\n function _resignImplementation() public;\n}\n" + }, + "contracts/ComptrollerG6.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/INV.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n */\ncontract ComptrollerG6 is ComptrollerV5Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError {\n /// @notice Emitted when an admin supports a market\n event MarketListed(CToken cToken);\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(CToken cToken, address account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(CToken cToken, address account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /// @notice Emitted when pause guardian is changed\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /// @notice Emitted when an action is paused globally\n event ActionPaused(string action, bool pauseState);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n /// @notice Emitted when market comped status is changed\n event MarketComped(CToken cToken, bool isComped);\n\n /// @notice Emitted when COMP rate is changed\n event NewCompRate(uint oldCompRate, uint newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);\n\n /// @notice Emitted when a new COMP speed is set for a contributor\n event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);\n\n /// @notice Emitted when COMP is granted by admin\n event CompGranted(address recipient, uint amount);\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint public constant compClaimThreshold = 0.001e18;\n\n /// @notice The initial COMP index for a market\n uint224 public constant compInitialIndex = 1e36;\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n\n uint borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint totalBorrows = CToken(cToken).totalBorrows();\n uint nextTotalBorrows = add_(totalBorrows, borrowAmount);\n require(nextTotalBorrows < borrowCap, \"market borrow cap reached\");\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower, false);\n distributeSupplierComp(cTokenCollateral, liquidator, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, src, false);\n distributeSupplierComp(cToken, dst, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToDenom;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);\n\n // sumCollateral += tokensToDenom * cTokenBalance\n vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}));\n denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {\n // Check caller is admin\n \trequire(msg.sender == admin, \"only admin can set close factor\");\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint i = 0; i < allMarkets.length; i ++) {\n require(allMarkets[i] != CToken(cToken), \"market already added\");\n }\n allMarkets.push(CToken(cToken));\n }\n\n\n /**\n * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing.\n * @param cTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing.\n */\n function _setMarketBorrowCaps(CToken[] calldata cTokens, uint[] calldata newBorrowCaps) external {\n \trequire(msg.sender == admin || msg.sender == borrowCapGuardian, \"only admin or borrow cap guardian can set borrow caps\"); \n\n uint numMarkets = cTokens.length;\n uint numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n for(uint i = 0; i < numMarkets; i++) {\n borrowCaps[address(cTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(cTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Admin function to change the Borrow Cap Guardian\n * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian\n */\n function _setBorrowCapGuardian(address newBorrowCapGuardian) external {\n require(msg.sender == admin, \"only admin can set borrow cap guardian\");\n\n // Save current value for inclusion in log\n address oldBorrowCapGuardian = borrowCapGuardian;\n\n // Store borrowCapGuardian with value newBorrowCapGuardian\n borrowCapGuardian = newBorrowCapGuardian;\n\n // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian)\n emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian);\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n require(unitroller._acceptImplementation() == 0, \"change not authorized\");\n }\n\n /**\n * @notice Checks caller is admin, or this contract is becoming the new implementation\n */\n function adminOrInitializing() internal view returns (bool) {\n return msg.sender == admin || msg.sender == comptrollerImplementation;\n }\n\n /*** Comp Distribution ***/\n\n /**\n * @notice Recalculate and update COMP speeds for all COMP markets\n */\n function refreshCompSpeeds() public {\n require(msg.sender == tx.origin, \"only externally owned accounts may refresh speeds\");\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompSupplyIndex(address(cToken));\n updateCompBorrowIndex(address(cToken), borrowIndex);\n }\n\n Exp memory totalUtility = Exp({mantissa: 0});\n Exp[] memory utilities = new Exp[](allMarkets_.length);\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({mantissa: oracle.getUnderlyingPrice(cToken)});\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint newSpeed = totalUtility.mantissa > 0 ? mul_(compRate, div_(utilities[i], totalUtility)) : 0;\n compSpeeds[address(cToken)] = newSpeed;\n emit CompSpeedUpdated(cToken, newSpeed);\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the supply index\n * @param cToken The market whose supply index to update\n */\n function updateCompSupplyIndex(address cToken) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n uint supplySpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint supplyTokens = CToken(cToken).totalSupply();\n uint compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: supplyState.index}), ratio);\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the borrow index\n * @param cToken The market whose borrow index to update\n */\n function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint borrowSpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint borrowAmount = div_(CToken(cToken).totalBorrows(), marketBorrowIndex);\n uint compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(compAccrued, borrowAmount) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: borrowState.index}), ratio);\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Calculate COMP accrued by a supplier and possibly transfer it to them\n * @param cToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute COMP to\n */\n function distributeSupplierComp(address cToken, address supplier, bool distributeAll) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});\n compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;\n\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {\n supplierIndex.mantissa = compInitialIndex;\n }\n\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint supplierTokens = CToken(cToken).balanceOf(supplier);\n uint supplierDelta = mul_(supplierTokens, deltaIndex);\n uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);\n }\n\n /**\n * @notice Calculate COMP accrued by a borrower and possibly transfer it to them\n * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.\n * @param cToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute COMP to\n */\n function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex, bool distributeAll) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);\n compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);\n }\n }\n\n /**\n * @notice Transfer COMP to the user, if they are above the threshold\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param userAccrued The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {\n if (userAccrued >= threshold && userAccrued > 0) {\n INV comp = INV(getCompAddress());\n uint compRemaining = comp.balanceOf(address(this));\n if (userAccrued <= compRemaining) {\n comp.transfer(user, userAccrued);\n return 0;\n }\n }\n return userAccrued;\n }\n\n /**\n * @notice Calculate additional accrued COMP for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint compSpeed = compContributorSpeeds[contributor];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && compSpeed > 0) {\n uint newAccrued = mul_(deltaBlocks, compSpeed);\n uint contributorAccrued = add_(compAccrued[contributor], newAccrued);\n\n compAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n }\n }\n\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) public {\n return claimComp(holder, allMarkets);\n }\n\n /**\n * @notice Claim all the comp accrued by holder in the specified markets\n * @param holder The address to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n */\n function claimComp(address holder, CToken[] memory cTokens) public {\n address[] memory holders = new address[](1);\n holders[0] = holder;\n claimComp(holders, cTokens, true, true);\n }\n\n /**\n * @notice Claim all comp accrued by the holders\n * @param holders The addresses to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n * @param borrowers Whether or not to claim COMP earned by borrowing\n * @param suppliers Whether or not to claim COMP earned by supplying\n */\n function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {\n for (uint i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"market must be listed\");\n if (borrowers == true) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompBorrowIndex(address(cToken), borrowIndex);\n for (uint j = 0; j < holders.length; j++) {\n distributeBorrowerComp(address(cToken), holders[j], borrowIndex, true);\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j], true);\n }\n }\n }\n }\n\n /**\n * @notice Transfer COMP to the user\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param amount The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function grantCompInternal(address user, uint amount) internal returns (uint) {\n INV comp = INV(getCompAddress());\n uint compRemaining = comp.balanceOf(address(this));\n if (amount <= compRemaining) {\n comp.transfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /*** Comp Distribution Admin ***/\n\n /**\n * @notice Transfer COMP to the recipient\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param recipient The address of the recipient to transfer COMP to\n * @param amount The amount of COMP to (possibly) transfer\n */\n function _grantComp(address recipient, uint amount) public {\n require(adminOrInitializing(), \"only admin can grant comp\");\n uint amountLeft = grantCompInternal(recipient, amount);\n require(amountLeft == 0, \"insufficient comp for grant\");\n emit CompGranted(recipient, amount);\n }\n\n /**\n * @notice Set COMP speed for a single contributor\n * @param contributor The contributor whose COMP speed to update\n * @param compSpeed New COMP speed for contributor\n */\n function _setContributorCompSpeed(address contributor, uint compSpeed) public {\n require(adminOrInitializing(), \"only admin can set comp speed\");\n\n // note that COMP speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (compSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n }\n lastContributorBlock[contributor] = getBlockNumber();\n compContributorSpeeds[contributor] = compSpeed;\n\n emit ContributorCompSpeedUpdated(contributor, compSpeed);\n }\n\n /**\n * @notice Set the amount of COMP distributed per block\n * @param compRate_ The amount of COMP wei per block to distribute\n */\n function _setCompRate(uint compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint oldRate = compRate;\n compRate = compRate_;\n emit NewCompRate(oldRate, compRate_);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel\n * @param cTokens The addresses of the markets to add\n */\n function _addCompMarkets(address[] memory cTokens) public {\n require(adminOrInitializing(), \"only admin can add comp market\");\n\n for (uint i = 0; i < cTokens.length; i++) {\n _addCompMarketInternal(cTokens[i]);\n }\n\n refreshCompSpeedsInternal();\n }\n\n function _addCompMarketInternal(address cToken) internal {\n Market storage market = markets[cToken];\n require(market.isListed == true, \"comp market is not listed\");\n require(market.isComped == false, \"comp market already added\");\n\n market.isComped = true;\n emit MarketComped(CToken(cToken), true);\n\n if (compSupplyState[cToken].index == 0 && compSupplyState[cToken].block == 0) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (compBorrowState[cToken].index == 0 && compBorrowState[cToken].block == 0) {\n compBorrowState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n }\n\n /**\n * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel\n * @param cToken The address of the market to drop\n */\n function _dropCompMarket(address cToken) public {\n require(msg.sender == admin, \"only admin can drop comp market\");\n\n Market storage market = markets[cToken];\n require(market.isComped == true, \"market is not a comp market\");\n\n market.isComped = false;\n emit MarketComped(CToken(cToken), false);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return The list of market addresses\n */\n function getAllMarkets() public view returns (CToken[] memory) {\n return allMarkets;\n }\n\n function getBlockNumber() public view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Return the address of the COMP token\n * @return The address of COMP\n */\n function getCompAddress() public view returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" + }, + "contracts/Governance/INV.sol": { + "content": "pragma solidity ^0.5.16;\n\npragma experimental ABIEncoderV2;\n\nimport \"../SafeMath.sol\";\n\ncontract INV {\n /// @notice EIP-20 token name for this token\n string public constant name = \"Inverse DAO\";\n\n /// @notice EIP-20 token symbol for this token\n string public constant symbol = \"INV\";\n\n /// @notice EIP-20 token decimals for this token\n uint8 public constant decimals = 18;\n\n /// @notice Total number of tokens in circulation\n uint public totalSupply = 100000e18; // 100k\n\n /// @notice Address which may mint new tokens\n address public owner;\n\n bool public tradable;\n bool public seizable = true;\n\n mapping (address => bool) public whitelist; // addresses allowed to send when non-tradable\n\n /// @notice Allowance amounts on behalf of others\n mapping (address => mapping (address => uint96)) internal allowances;\n\n /// @notice Official record of token balances for each account\n mapping (address => uint96) internal balances;\n\n /// @notice A record of each accounts delegate\n mapping (address => address) public delegates;\n\n /// @notice A checkpoint for marking number of votes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 votes;\n }\n\n /// @notice A record of votes checkpoints for each account, by index\n mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;\n\n /// @notice The number of checkpoints for each account\n mapping (address => uint32) public numCheckpoints;\n\n /// @notice The EIP-712 typehash for the contract's domain\n bytes32 public constant DOMAIN_TYPEHASH = keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract\n bytes32 public constant DELEGATION_TYPEHASH = keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n /// @notice The EIP-712 typehash for the permit struct used by the contract\n bytes32 public constant PERMIT_TYPEHASH = keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /// @notice A record of states for signing / validating signatures\n mapping (address => uint) public nonces;\n\n /// @notice An event thats emitted when the owner address is changed\n event OwnerChanged(address owner, address newOwner);\n\n /// @notice An event thats emitted when an account changes its delegate\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /// @notice An event thats emitted when a delegate account's vote balance changes\n event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);\n\n /// @notice The standard EIP-20 transfer event\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /// @notice The standard EIP-20 approval event\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n modifier onlyOwner {\n require(msg.sender == owner, \"INV: only the owner can call this method\");\n _;\n }\n\n /**\n * @notice Construct a new token\n * @param account The initial account to grant all the tokens\n */\n constructor(address account) public {\n\n balances[account] = uint96(totalSupply);\n emit Transfer(address(0), account, totalSupply);\n owner = account;\n emit OwnerChanged(address(0), account);\n whitelist[account] = true;\n }\n\n /**\n * @notice Change the owner address\n * @param owner_ The address of the new owner\n */\n function setOwner(address owner_) external onlyOwner {\n emit OwnerChanged(owner, owner_);\n owner = owner_;\n }\n\n function seize(address src, uint rawAmount) external onlyOwner {\n require(seizable);\n uint96 amount = safe96(rawAmount, \"INV::seize: amount exceeds 96 bits\");\n totalSupply = safe96(SafeMath.sub(totalSupply, amount), \"INV::seize: totalSupply exceeds 96 bits\");\n\n balances[src] = sub96(balances[src], amount, \"INV::seize: transfer amount overflows\");\n emit Transfer(src, address(0), amount);\n\n // move delegates\n _moveDelegates(delegates[src], address(0), amount);\n }\n\n // makes token transferrable. Also abolishes seizing irreversibly.\n function openTheGates() external onlyOwner {\n seizable = false;\n tradable = true;\n }\n\n function closeTheGates() external onlyOwner {\n tradable = false;\n }\n\n // one way function\n function abolishSeizing() external onlyOwner {\n seizable = false;\n }\n\n function addToWhitelist(address _user) external onlyOwner {\n whitelist[_user] = true;\n }\n\n function removeFromWhitelist(address _user) external onlyOwner {\n whitelist[_user] = false;\n }\n\n /**\n * @notice Mint new tokens\n * @param dst The address of the destination account\n * @param rawAmount The number of tokens to be minted\n */\n function mint(address dst, uint rawAmount) external {\n require(msg.sender == owner, \"INV::mint: only the owner can mint\");\n require(dst != address(0), \"INV::mint: cannot transfer to the zero address\");\n\n // mint the amount\n uint96 amount = safe96(rawAmount, \"INV::mint: amount exceeds 96 bits\");\n totalSupply = safe96(SafeMath.add(totalSupply, amount), \"INV::mint: totalSupply exceeds 96 bits\");\n\n // transfer the amount to the recipient\n balances[dst] = add96(balances[dst], amount, \"INV::mint: transfer amount overflows\");\n emit Transfer(address(0), dst, amount);\n\n // move delegates\n _moveDelegates(address(0), delegates[dst], amount);\n }\n\n /**\n * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`\n * @param account The address of the account holding the funds\n * @param spender The address of the account spending the funds\n * @return The number of tokens approved\n */\n function allowance(address account, address spender) external view returns (uint) {\n return allowances[account][spender];\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)\n * @return Whether or not the approval succeeded\n */\n function approve(address spender, uint rawAmount) external returns (bool) {\n uint96 amount;\n if (rawAmount == uint(-1)) {\n amount = uint96(-1);\n } else {\n amount = safe96(rawAmount, \"INV::approve: amount exceeds 96 bits\");\n }\n\n allowances[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n return true;\n }\n\n /**\n * @notice Triggers an approval from owner to spends\n * @param _owner The address to approve from\n * @param spender The address to be approved\n * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)\n * @param deadline The time at which to expire the signature\n * @param v The recovery byte of the signature\n * @param r Half of the ECDSA signature pair\n * @param s Half of the ECDSA signature pair\n */\n function permit(address _owner, address spender, uint rawAmount, uint deadline, uint8 v, bytes32 r, bytes32 s) external {\n uint96 amount;\n if (rawAmount == uint(-1)) {\n amount = uint96(-1);\n } else {\n amount = safe96(rawAmount, \"INV::permit: amount exceeds 96 bits\");\n }\n\n bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));\n bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, _owner, spender, rawAmount, nonces[_owner]++, deadline));\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n require(signatory != address(0), \"INV::permit: invalid signature\");\n require(signatory == _owner, \"INV::permit: unauthorized\");\n require(now <= deadline, \"INV::permit: signature expired\");\n\n allowances[_owner][spender] = amount;\n\n emit Approval(_owner, spender, amount);\n }\n\n /**\n * @notice Get the number of tokens held by the `account`\n * @param account The address of the account to get the balance of\n * @return The number of tokens held\n */\n function balanceOf(address account) external view returns (uint) {\n return balances[account];\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param rawAmount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transfer(address dst, uint rawAmount) external returns (bool) {\n uint96 amount = safe96(rawAmount, \"INV::transfer: amount exceeds 96 bits\");\n _transferTokens(msg.sender, dst, amount);\n return true;\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param rawAmount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transferFrom(address src, address dst, uint rawAmount) external returns (bool) {\n address spender = msg.sender;\n uint96 spenderAllowance = allowances[src][spender];\n uint96 amount = safe96(rawAmount, \"INV::approve: amount exceeds 96 bits\");\n\n if (spender != src && spenderAllowance != uint96(-1)) {\n uint96 newAllowance = sub96(spenderAllowance, amount, \"INV::transferFrom: transfer amount exceeds spender allowance\");\n allowances[src][spender] = newAllowance;\n\n emit Approval(src, spender, newAllowance);\n }\n\n _transferTokens(src, dst, amount);\n return true;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` to `delegatee`\n * @param delegatee The address to delegate votes to\n */\n function delegate(address delegatee) public {\n return _delegate(msg.sender, delegatee);\n }\n\n /**\n * @notice Delegates votes from signatory to `delegatee`\n * @param delegatee The address to delegate votes to\n * @param nonce The contract state required to match the signature\n * @param expiry The time at which to expire the signature\n * @param v The recovery byte of the signature\n * @param r Half of the ECDSA signature pair\n * @param s Half of the ECDSA signature pair\n */\n function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public {\n bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));\n bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n require(signatory != address(0), \"INV::delegateBySig: invalid signature\");\n require(nonce == nonces[signatory]++, \"INV::delegateBySig: invalid nonce\");\n require(now <= expiry, \"INV::delegateBySig: signature expired\");\n return _delegate(signatory, delegatee);\n }\n\n /**\n * @notice Gets the current votes balance for `account`\n * @param account The address to get votes balance\n * @return The number of current votes for `account`\n */\n function getCurrentVotes(address account) external view returns (uint96) {\n uint32 nCheckpoints = numCheckpoints[account];\n return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\n }\n\n /**\n * @notice Determine the prior number of votes for an account as of a block number\n * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\n * @param account The address of the account to check\n * @param blockNumber The block number to get the vote balance at\n * @return The number of votes the account had as of the given block\n */\n function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {\n require(blockNumber < block.number, \"INV::getPriorVotes: not yet determined\");\n\n uint32 nCheckpoints = numCheckpoints[account];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\n return checkpoints[account][nCheckpoints - 1].votes;\n }\n\n // Next check implicit zero balance\n if (checkpoints[account][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = checkpoints[account][center];\n if (cp.fromBlock == blockNumber) {\n return cp.votes;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return checkpoints[account][lower].votes;\n }\n\n function _delegate(address delegator, address delegatee) internal {\n address currentDelegate = delegates[delegator];\n uint96 delegatorBalance = balances[delegator];\n delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _transferTokens(address src, address dst, uint96 amount) internal {\n require(src != address(0), \"INV::_transferTokens: cannot transfer from the zero address\");\n require(dst != address(0), \"INV::_transferTokens: cannot transfer to the zero address\");\n\n if(!tradable) {\n require(whitelist[src], \"INV::_transferTokens: src not whitelisted\");\n }\n\n balances[src] = sub96(balances[src], amount, \"INV::_transferTokens: transfer amount exceeds balance\");\n balances[dst] = add96(balances[dst], amount, \"INV::_transferTokens: transfer amount overflows\");\n emit Transfer(src, dst, amount);\n\n _moveDelegates(delegates[src], delegates[dst], amount);\n }\n\n function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) {\n uint32 srcRepNum = numCheckpoints[srcRep];\n uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\n uint96 srcRepNew = sub96(srcRepOld, amount, \"INV::_moveVotes: vote amount underflows\");\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\n }\n\n if (dstRep != address(0)) {\n uint32 dstRepNum = numCheckpoints[dstRep];\n uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\n uint96 dstRepNew = add96(dstRepOld, amount, \"INV::_moveVotes: vote amount overflows\");\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\n }\n }\n }\n\n function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {\n uint32 blockNumber = safe32(block.number, \"INV::_writeCheckpoint: block number exceeds 32 bits\");\n\n if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\n } else {\n checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\n numCheckpoints[delegatee] = nCheckpoints + 1;\n }\n\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\n }\n\n function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n function getChainId() internal pure returns (uint) {\n uint256 chainId;\n assembly { chainId := chainid() }\n return chainId;\n }\n}" + }, + "contracts/ComptrollerG5.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/INV.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound (modified by Arr00)\n */\ncontract ComptrollerG5 is ComptrollerV4Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {\n /// @notice Emitted when an admin supports a market\n event MarketListed(CToken cToken);\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(CToken cToken, address account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(CToken cToken, address account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /// @notice Emitted when pause guardian is changed\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /// @notice Emitted when an action is paused globally\n event ActionPaused(string action, bool pauseState);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n /// @notice Emitted when market comped status is changed\n event MarketComped(CToken cToken, bool isComped);\n\n /// @notice Emitted when COMP rate is changed\n event NewCompRate(uint oldCompRate, uint newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);\n\n /// @notice Emitted when borrow cap for a cToken is changed\n event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);\n\n /// @notice Emitted when borrow cap guardian is changed\n event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint public constant compClaimThreshold = 0.001e18;\n\n /// @notice The initial COMP index for a market\n uint224 public constant compInitialIndex = 1e36;\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n if (accountAssets[borrower].length >= maxAssets) {\n // no space, cannot join\n return Error.TOO_MANY_ASSETS;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n\n uint borrowCap = borrowCaps[cToken];\n // Borrow cap of 0 corresponds to unlimited borrowing\n if (borrowCap != 0) {\n uint totalBorrows = CToken(cToken).totalBorrows();\n (MathError mathErr, uint nextTotalBorrows) = addUInt(totalBorrows, borrowAmount);\n require(mathErr == MathError.NO_ERROR, \"total borrows overflow\");\n require(nextTotalBorrows < borrowCap, \"market borrow cap reached\");\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (mathErr != MathError.NO_ERROR) {\n return uint(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower, false);\n distributeSupplierComp(cTokenCollateral, liquidator, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, src, false);\n distributeSupplierComp(cToken, dst, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToDenom;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n (mErr, vars.tokensToDenom) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets maxAssets which controls how many markets can be entered\n * @dev Admin function to set maxAssets\n * @param newMaxAssets New max assets\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setMaxAssets(uint newMaxAssets) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);\n }\n\n uint oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa});\n Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa});\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa});\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint i = 0; i < allMarkets.length; i ++) {\n require(allMarkets[i] != CToken(cToken), \"market already added\");\n }\n allMarkets.push(CToken(cToken));\n }\n\n\n /**\n * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing.\n * @param cTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing.\n */\n function _setMarketBorrowCaps(CToken[] calldata cTokens, uint[] calldata newBorrowCaps) external {\n \trequire(msg.sender == admin || msg.sender == borrowCapGuardian, \"only admin or borrow cap guardian can set borrow caps\"); \n\n uint numMarkets = cTokens.length;\n uint numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n for(uint i = 0; i < numMarkets; i++) {\n borrowCaps[address(cTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(cTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Admin function to change the Borrow Cap Guardian\n * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian\n */\n function _setBorrowCapGuardian(address newBorrowCapGuardian) external {\n require(msg.sender == admin, \"only admin can set borrow cap guardian\");\n\n // Save current value for inclusion in log\n address oldBorrowCapGuardian = borrowCapGuardian;\n\n // Store borrowCapGuardian with value newBorrowCapGuardian\n borrowCapGuardian = newBorrowCapGuardian;\n\n // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian)\n emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian);\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n require(unitroller._acceptImplementation() == 0, \"change not authorized\");\n }\n\n /**\n * @notice Checks caller is admin, or this contract is becoming the new implementation\n */\n function adminOrInitializing() internal view returns (bool) {\n return msg.sender == admin || msg.sender == comptrollerImplementation;\n }\n\n /*** Comp Distribution ***/\n\n /**\n * @notice Recalculate and update COMP speeds for all COMP markets\n */\n function refreshCompSpeeds() public {\n require(msg.sender == tx.origin, \"only externally owned accounts may refresh speeds\");\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompSupplyIndex(address(cToken));\n updateCompBorrowIndex(address(cToken), borrowIndex);\n }\n\n Exp memory totalUtility = Exp({mantissa: 0});\n Exp[] memory utilities = new Exp[](allMarkets_.length);\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({mantissa: oracle.getUnderlyingPrice(cToken)});\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint newSpeed = totalUtility.mantissa > 0 ? mul_(compRate, div_(utilities[i], totalUtility)) : 0;\n compSpeeds[address(cToken)] = newSpeed;\n emit CompSpeedUpdated(cToken, newSpeed);\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the supply index\n * @param cToken The market whose supply index to update\n */\n function updateCompSupplyIndex(address cToken) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n uint supplySpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint supplyTokens = CToken(cToken).totalSupply();\n uint compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: supplyState.index}), ratio);\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the borrow index\n * @param cToken The market whose borrow index to update\n */\n function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint borrowSpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint borrowAmount = div_(CToken(cToken).totalBorrows(), marketBorrowIndex);\n uint compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(compAccrued, borrowAmount) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: borrowState.index}), ratio);\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Calculate COMP accrued by a supplier and possibly transfer it to them\n * @param cToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute COMP to\n */\n function distributeSupplierComp(address cToken, address supplier, bool distributeAll) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});\n compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;\n\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {\n supplierIndex.mantissa = compInitialIndex;\n }\n\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint supplierTokens = CToken(cToken).balanceOf(supplier);\n uint supplierDelta = mul_(supplierTokens, deltaIndex);\n uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);\n }\n\n /**\n * @notice Calculate COMP accrued by a borrower and possibly transfer it to them\n * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.\n * @param cToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute COMP to\n */\n function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex, bool distributeAll) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);\n compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);\n }\n }\n\n /**\n * @notice Transfer COMP to the user, if they are above the threshold\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param userAccrued The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {\n if (userAccrued >= threshold && userAccrued > 0) {\n INV comp = INV(getCompAddress());\n uint compRemaining = comp.balanceOf(address(this));\n if (userAccrued <= compRemaining) {\n comp.transfer(user, userAccrued);\n return 0;\n }\n }\n return userAccrued;\n }\n\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) public {\n return claimComp(holder, allMarkets);\n }\n\n /**\n * @notice Claim all the comp accrued by holder in the specified markets\n * @param holder The address to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n */\n function claimComp(address holder, CToken[] memory cTokens) public {\n address[] memory holders = new address[](1);\n holders[0] = holder;\n claimComp(holders, cTokens, true, true);\n }\n\n /**\n * @notice Claim all comp accrued by the holders\n * @param holders The addresses to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n * @param borrowers Whether or not to claim COMP earned by borrowing\n * @param suppliers Whether or not to claim COMP earned by supplying\n */\n function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {\n for (uint i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"market must be listed\");\n if (borrowers == true) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompBorrowIndex(address(cToken), borrowIndex);\n for (uint j = 0; j < holders.length; j++) {\n distributeBorrowerComp(address(cToken), holders[j], borrowIndex, true);\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j], true);\n }\n }\n }\n }\n\n /*** Comp Distribution Admin ***/\n\n /**\n * @notice Set the amount of COMP distributed per block\n * @param compRate_ The amount of COMP wei per block to distribute\n */\n function _setCompRate(uint compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint oldRate = compRate;\n compRate = compRate_;\n emit NewCompRate(oldRate, compRate_);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel\n * @param cTokens The addresses of the markets to add\n */\n function _addCompMarkets(address[] memory cTokens) public {\n require(adminOrInitializing(), \"only admin can add comp market\");\n\n for (uint i = 0; i < cTokens.length; i++) {\n _addCompMarketInternal(cTokens[i]);\n }\n\n refreshCompSpeedsInternal();\n }\n\n function _addCompMarketInternal(address cToken) internal {\n Market storage market = markets[cToken];\n require(market.isListed == true, \"comp market is not listed\");\n require(market.isComped == false, \"comp market already added\");\n\n market.isComped = true;\n emit MarketComped(CToken(cToken), true);\n\n if (compSupplyState[cToken].index == 0 && compSupplyState[cToken].block == 0) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (compBorrowState[cToken].index == 0 && compBorrowState[cToken].block == 0) {\n compBorrowState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n }\n\n /**\n * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel\n * @param cToken The address of the market to drop\n */\n function _dropCompMarket(address cToken) public {\n require(msg.sender == admin, \"only admin can drop comp market\");\n\n Market storage market = markets[cToken];\n require(market.isComped == true, \"market is not a comp market\");\n\n market.isComped = false;\n emit MarketComped(CToken(cToken), false);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return The list of market addresses\n */\n function getAllMarkets() public view returns (CToken[] memory) {\n return allMarkets;\n }\n\n function getBlockNumber() public view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Return the address of the COMP token\n * @return The address of COMP\n */\n function getCompAddress() public view returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" + }, + "contracts/ComptrollerG4.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/INV.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n */\ncontract ComptrollerG4 is ComptrollerV3Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {\n /// @notice Emitted when an admin supports a market\n event MarketListed(CToken cToken);\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(CToken cToken, address account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(CToken cToken, address account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /// @notice Emitted when pause guardian is changed\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /// @notice Emitted when an action is paused globally\n event ActionPaused(string action, bool pauseState);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n /// @notice Emitted when market comped status is changed\n event MarketComped(CToken cToken, bool isComped);\n\n /// @notice Emitted when COMP rate is changed\n event NewCompRate(uint oldCompRate, uint newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint public constant compClaimThreshold = 0.001e18;\n\n /// @notice The initial COMP index for a market\n uint224 public constant compInitialIndex = 1e36;\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n if (accountAssets[borrower].length >= maxAssets) {\n // no space, cannot join\n return Error.TOO_MANY_ASSETS;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (mathErr != MathError.NO_ERROR) {\n return uint(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower, false);\n distributeSupplierComp(cTokenCollateral, liquidator, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, src, false);\n distributeSupplierComp(cToken, dst, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToDenom;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n (mErr, vars.tokensToDenom) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets maxAssets which controls how many markets can be entered\n * @dev Admin function to set maxAssets\n * @param newMaxAssets New max assets\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setMaxAssets(uint newMaxAssets) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);\n }\n\n uint oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa});\n Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa});\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa});\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint i = 0; i < allMarkets.length; i ++) {\n require(allMarkets[i] != CToken(cToken), \"market already added\");\n }\n allMarkets.push(CToken(cToken));\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n require(unitroller._acceptImplementation() == 0, \"change not authorized\");\n }\n\n /**\n * @notice Checks caller is admin, or this contract is becoming the new implementation\n */\n function adminOrInitializing() internal view returns (bool) {\n return msg.sender == admin || msg.sender == comptrollerImplementation;\n }\n\n /*** Comp Distribution ***/\n\n /**\n * @notice Recalculate and update COMP speeds for all COMP markets\n */\n function refreshCompSpeeds() public {\n require(msg.sender == tx.origin, \"only externally owned accounts may refresh speeds\");\n refreshCompSpeedsInternal();\n }\n\n function refreshCompSpeedsInternal() internal {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompSupplyIndex(address(cToken));\n updateCompBorrowIndex(address(cToken), borrowIndex);\n }\n\n Exp memory totalUtility = Exp({mantissa: 0});\n Exp[] memory utilities = new Exp[](allMarkets_.length);\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({mantissa: oracle.getUnderlyingPrice(cToken)});\n Exp memory utility = mul_(assetPrice, cToken.totalBorrows());\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint newSpeed = totalUtility.mantissa > 0 ? mul_(compRate, div_(utilities[i], totalUtility)) : 0;\n compSpeeds[address(cToken)] = newSpeed;\n emit CompSpeedUpdated(cToken, newSpeed);\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the supply index\n * @param cToken The market whose supply index to update\n */\n function updateCompSupplyIndex(address cToken) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n uint supplySpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint supplyTokens = CToken(cToken).totalSupply();\n uint compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: supplyState.index}), ratio);\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the borrow index\n * @param cToken The market whose borrow index to update\n */\n function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint borrowSpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint borrowAmount = div_(CToken(cToken).totalBorrows(), marketBorrowIndex);\n uint compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(compAccrued, borrowAmount) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: borrowState.index}), ratio);\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Calculate COMP accrued by a supplier and possibly transfer it to them\n * @param cToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute COMP to\n */\n function distributeSupplierComp(address cToken, address supplier, bool distributeAll) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});\n compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;\n\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {\n supplierIndex.mantissa = compInitialIndex;\n }\n\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint supplierTokens = CToken(cToken).balanceOf(supplier);\n uint supplierDelta = mul_(supplierTokens, deltaIndex);\n uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);\n }\n\n /**\n * @notice Calculate COMP accrued by a borrower and possibly transfer it to them\n * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.\n * @param cToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute COMP to\n */\n function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex, bool distributeAll) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);\n compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);\n }\n }\n\n /**\n * @notice Transfer COMP to the user, if they are above the threshold\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param userAccrued The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {\n if (userAccrued >= threshold && userAccrued > 0) {\n INV comp = INV(getCompAddress());\n uint compRemaining = comp.balanceOf(address(this));\n if (userAccrued <= compRemaining) {\n comp.transfer(user, userAccrued);\n return 0;\n }\n }\n return userAccrued;\n }\n\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) public {\n return claimComp(holder, allMarkets);\n }\n\n /**\n * @notice Claim all the comp accrued by holder in the specified markets\n * @param holder The address to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n */\n function claimComp(address holder, CToken[] memory cTokens) public {\n address[] memory holders = new address[](1);\n holders[0] = holder;\n claimComp(holders, cTokens, true, true);\n }\n\n /**\n * @notice Claim all comp accrued by the holders\n * @param holders The addresses to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n * @param borrowers Whether or not to claim COMP earned by borrowing\n * @param suppliers Whether or not to claim COMP earned by supplying\n */\n function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {\n for (uint i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"market must be listed\");\n if (borrowers == true) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompBorrowIndex(address(cToken), borrowIndex);\n for (uint j = 0; j < holders.length; j++) {\n distributeBorrowerComp(address(cToken), holders[j], borrowIndex, true);\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j], true);\n }\n }\n }\n }\n\n /*** Comp Distribution Admin ***/\n\n /**\n * @notice Set the amount of COMP distributed per block\n * @param compRate_ The amount of COMP wei per block to distribute\n */\n function _setCompRate(uint compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint oldRate = compRate;\n compRate = compRate_;\n emit NewCompRate(oldRate, compRate_);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel\n * @param cTokens The addresses of the markets to add\n */\n function _addCompMarkets(address[] memory cTokens) public {\n require(adminOrInitializing(), \"only admin can add comp market\");\n\n for (uint i = 0; i < cTokens.length; i++) {\n _addCompMarketInternal(cTokens[i]);\n }\n\n refreshCompSpeedsInternal();\n }\n\n function _addCompMarketInternal(address cToken) internal {\n Market storage market = markets[cToken];\n require(market.isListed == true, \"comp market is not listed\");\n require(market.isComped == false, \"comp market already added\");\n\n market.isComped = true;\n emit MarketComped(CToken(cToken), true);\n\n if (compSupplyState[cToken].index == 0 && compSupplyState[cToken].block == 0) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (compBorrowState[cToken].index == 0 && compBorrowState[cToken].block == 0) {\n compBorrowState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n }\n\n /**\n * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel\n * @param cToken The address of the market to drop\n */\n function _dropCompMarket(address cToken) public {\n require(msg.sender == admin, \"only admin can drop comp market\");\n\n Market storage market = markets[cToken];\n require(market.isComped == true, \"market is not a comp market\");\n\n market.isComped = false;\n emit MarketComped(CToken(cToken), false);\n\n refreshCompSpeedsInternal();\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return The list of market addresses\n */\n function getAllMarkets() public view returns (CToken[] memory) {\n return allMarkets;\n }\n\n function getBlockNumber() public view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Return the address of the COMP token\n * @return The address of COMP\n */\n function getCompAddress() public view returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" + }, + "contracts/ComptrollerG3.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\nimport \"./Governance/INV.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n */\ncontract ComptrollerG3 is ComptrollerV3Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {\n /// @notice Emitted when an admin supports a market\n event MarketListed(CToken cToken);\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(CToken cToken, address account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(CToken cToken, address account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when maxAssets is changed by admin\n event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /// @notice Emitted when pause guardian is changed\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /// @notice Emitted when an action is paused globally\n event ActionPaused(string action, bool pauseState);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n /// @notice Emitted when market comped status is changed\n event MarketComped(CToken cToken, bool isComped);\n\n /// @notice Emitted when COMP rate is changed\n event NewCompRate(uint oldCompRate, uint newCompRate);\n\n /// @notice Emitted when a new COMP speed is calculated for a market\n event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);\n\n /// @notice Emitted when COMP is distributed to a supplier\n event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);\n\n /// @notice Emitted when COMP is distributed to a borrower\n event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);\n\n /// @notice The threshold above which the flywheel transfers COMP, in wei\n uint public constant compClaimThreshold = 0.001e18;\n\n /// @notice The initial COMP index for a market\n uint224 public constant compInitialIndex = 1e36;\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n if (accountAssets[borrower].length >= maxAssets) {\n // no space, cannot join\n return Error.TOO_MANY_ASSETS;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing neccessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, minter, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, redeemer, false);\n\n return uint(Error.NO_ERROR);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // Keep the flywheel moving\n Exp memory borrowIndex = Exp({mantissa: CToken(cToken).borrowIndex()});\n updateCompBorrowIndex(cToken, borrowIndex);\n distributeBorrowerComp(cToken, borrower, borrowIndex, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (mathErr != MathError.NO_ERROR) {\n return uint(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cTokenCollateral);\n distributeSupplierComp(cTokenCollateral, borrower, false);\n distributeSupplierComp(cTokenCollateral, liquidator, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n uint allowed = redeemAllowedInternal(cToken, src, transferTokens);\n if (allowed != uint(Error.NO_ERROR)) {\n return allowed;\n }\n\n // Keep the flywheel moving\n updateCompSupplyIndex(cToken);\n distributeSupplierComp(cToken, src, false);\n distributeSupplierComp(cToken, dst, false);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToDenom;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n (mErr, vars.tokensToDenom) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToDenom * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToDenom * redeemTokens\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets maxAssets which controls how many markets can be entered\n * @dev Admin function to set maxAssets\n * @param newMaxAssets New max assets\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setMaxAssets(uint newMaxAssets) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);\n }\n\n uint oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa});\n Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa});\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa});\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n\n _addMarketInternal(address(cToken));\n\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _addMarketInternal(address cToken) internal {\n for (uint i = 0; i < allMarkets.length; i ++) {\n require(allMarkets[i] != CToken(cToken), \"market already added\");\n }\n allMarkets.push(CToken(cToken));\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller, uint compRate_, address[] memory compMarketsToAdd, address[] memory otherMarketsToAdd) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n require(unitroller._acceptImplementation() == 0, \"change not authorized\");\n\n ComptrollerG3(address(unitroller))._becomeG3(compRate_, compMarketsToAdd, otherMarketsToAdd);\n }\n\n function _becomeG3(uint compRate_, address[] memory compMarketsToAdd, address[] memory otherMarketsToAdd) public {\n require(msg.sender == comptrollerImplementation, \"only brains can become itself\");\n\n for (uint i = 0; i < compMarketsToAdd.length; i++) {\n _addMarketInternal(address(compMarketsToAdd[i]));\n }\n\n for (uint i = 0; i < otherMarketsToAdd.length; i++) {\n _addMarketInternal(address(otherMarketsToAdd[i]));\n }\n\n _setCompRate(compRate_);\n _addCompMarkets(compMarketsToAdd);\n }\n\n /**\n * @notice Checks caller is admin, or this contract is becoming the new implementation\n */\n function adminOrInitializing() internal view returns (bool) {\n return msg.sender == admin || msg.sender == comptrollerImplementation;\n }\n\n /*** Comp Distribution ***/\n\n /**\n * @notice Recalculate and update COMP speeds for all COMP markets\n */\n function refreshCompSpeeds() public {\n CToken[] memory allMarkets_ = allMarkets;\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompSupplyIndex(address(cToken));\n updateCompBorrowIndex(address(cToken), borrowIndex);\n }\n\n Exp memory totalUtility = Exp({mantissa: 0});\n Exp[] memory utilities = new Exp[](allMarkets_.length);\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets_[i];\n if (markets[address(cToken)].isComped) {\n Exp memory assetPrice = Exp({mantissa: oracle.getUnderlyingPrice(cToken)});\n Exp memory interestPerBlock = mul_(Exp({mantissa: cToken.borrowRatePerBlock()}), cToken.totalBorrows());\n Exp memory utility = mul_(interestPerBlock, assetPrice);\n utilities[i] = utility;\n totalUtility = add_(totalUtility, utility);\n }\n }\n\n for (uint i = 0; i < allMarkets_.length; i++) {\n CToken cToken = allMarkets[i];\n uint newSpeed = totalUtility.mantissa > 0 ? mul_(compRate, div_(utilities[i], totalUtility)) : 0;\n compSpeeds[address(cToken)] = newSpeed;\n emit CompSpeedUpdated(cToken, newSpeed);\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the supply index\n * @param cToken The market whose supply index to update\n */\n function updateCompSupplyIndex(address cToken) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n uint supplySpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint supplyTokens = CToken(cToken).totalSupply();\n uint compAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(compAccrued, supplyTokens) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: supplyState.index}), ratio);\n compSupplyState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Accrue COMP to the market by updating the borrow index\n * @param cToken The market whose borrow index to update\n */\n function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n uint borrowSpeed = compSpeeds[cToken];\n uint blockNumber = getBlockNumber();\n uint deltaBlocks = sub_(blockNumber, uint(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint borrowAmount = div_(CToken(cToken).totalBorrows(), marketBorrowIndex);\n uint compAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(compAccrued, borrowAmount) : Double({mantissa: 0});\n Double memory index = add_(Double({mantissa: borrowState.index}), ratio);\n compBorrowState[cToken] = CompMarketState({\n index: safe224(index.mantissa, \"new index exceeds 224 bits\"),\n block: safe32(blockNumber, \"block number exceeds 32 bits\")\n });\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number exceeds 32 bits\");\n }\n }\n\n /**\n * @notice Calculate COMP accrued by a supplier and possibly transfer it to them\n * @param cToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute COMP to\n */\n function distributeSupplierComp(address cToken, address supplier, bool distributeAll) internal {\n CompMarketState storage supplyState = compSupplyState[cToken];\n Double memory supplyIndex = Double({mantissa: supplyState.index});\n Double memory supplierIndex = Double({mantissa: compSupplierIndex[cToken][supplier]});\n compSupplierIndex[cToken][supplier] = supplyIndex.mantissa;\n\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {\n supplierIndex.mantissa = compInitialIndex;\n }\n\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint supplierTokens = CToken(cToken).balanceOf(supplier);\n uint supplierDelta = mul_(supplierTokens, deltaIndex);\n uint supplierAccrued = add_(compAccrued[supplier], supplierDelta);\n compAccrued[supplier] = transferComp(supplier, supplierAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex.mantissa);\n }\n\n /**\n * @notice Calculate COMP accrued by a borrower and possibly transfer it to them\n * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.\n * @param cToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute COMP to\n */\n function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex, bool distributeAll) internal {\n CompMarketState storage borrowState = compBorrowState[cToken];\n Double memory borrowIndex = Double({mantissa: borrowState.index});\n Double memory borrowerIndex = Double({mantissa: compBorrowerIndex[cToken][borrower]});\n compBorrowerIndex[cToken][borrower] = borrowIndex.mantissa;\n\n if (borrowerIndex.mantissa > 0) {\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint borrowerAmount = div_(CToken(cToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint borrowerDelta = mul_(borrowerAmount, deltaIndex);\n uint borrowerAccrued = add_(compAccrued[borrower], borrowerDelta);\n compAccrued[borrower] = transferComp(borrower, borrowerAccrued, distributeAll ? 0 : compClaimThreshold);\n emit DistributedBorrowerComp(CToken(cToken), borrower, borrowerDelta, borrowIndex.mantissa);\n }\n }\n\n /**\n * @notice Transfer COMP to the user, if they are above the threshold\n * @dev Note: If there is not enough COMP, we do not perform the transfer all.\n * @param user The address of the user to transfer COMP to\n * @param userAccrued The amount of COMP to (possibly) transfer\n * @return The amount of COMP which was NOT transferred to the user\n */\n function transferComp(address user, uint userAccrued, uint threshold) internal returns (uint) {\n if (userAccrued >= threshold && userAccrued > 0) {\n INV comp = INV(getCompAddress());\n uint compRemaining = comp.balanceOf(address(this));\n if (userAccrued <= compRemaining) {\n comp.transfer(user, userAccrued);\n return 0;\n }\n }\n return userAccrued;\n }\n\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) public {\n return claimComp(holder, allMarkets);\n }\n\n /**\n * @notice Claim all the comp accrued by holder in the specified markets\n * @param holder The address to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n */\n function claimComp(address holder, CToken[] memory cTokens) public {\n address[] memory holders = new address[](1);\n holders[0] = holder;\n claimComp(holders, cTokens, true, true);\n }\n\n /**\n * @notice Claim all comp accrued by the holders\n * @param holders The addresses to claim COMP for\n * @param cTokens The list of markets to claim COMP in\n * @param borrowers Whether or not to claim COMP earned by borrowing\n * @param suppliers Whether or not to claim COMP earned by supplying\n */\n function claimComp(address[] memory holders, CToken[] memory cTokens, bool borrowers, bool suppliers) public {\n for (uint i = 0; i < cTokens.length; i++) {\n CToken cToken = cTokens[i];\n require(markets[address(cToken)].isListed, \"market must be listed\");\n if (borrowers == true) {\n Exp memory borrowIndex = Exp({mantissa: cToken.borrowIndex()});\n updateCompBorrowIndex(address(cToken), borrowIndex);\n for (uint j = 0; j < holders.length; j++) {\n distributeBorrowerComp(address(cToken), holders[j], borrowIndex, true);\n }\n }\n if (suppliers == true) {\n updateCompSupplyIndex(address(cToken));\n for (uint j = 0; j < holders.length; j++) {\n distributeSupplierComp(address(cToken), holders[j], true);\n }\n }\n }\n }\n\n /*** Comp Distribution Admin ***/\n\n /**\n * @notice Set the amount of COMP distributed per block\n * @param compRate_ The amount of COMP wei per block to distribute\n */\n function _setCompRate(uint compRate_) public {\n require(adminOrInitializing(), \"only admin can change comp rate\");\n\n uint oldRate = compRate;\n compRate = compRate_;\n emit NewCompRate(oldRate, compRate_);\n\n refreshCompSpeeds();\n }\n\n /**\n * @notice Add markets to compMarkets, allowing them to earn COMP in the flywheel\n * @param cTokens The addresses of the markets to add\n */\n function _addCompMarkets(address[] memory cTokens) public {\n require(adminOrInitializing(), \"only admin can add comp market\");\n\n for (uint i = 0; i < cTokens.length; i++) {\n _addCompMarketInternal(cTokens[i]);\n }\n\n refreshCompSpeeds();\n }\n\n function _addCompMarketInternal(address cToken) internal {\n Market storage market = markets[cToken];\n require(market.isListed == true, \"comp market is not listed\");\n require(market.isComped == false, \"comp market already added\");\n\n market.isComped = true;\n emit MarketComped(CToken(cToken), true);\n\n if (compSupplyState[cToken].index == 0 && compSupplyState[cToken].block == 0) {\n compSupplyState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n\n if (compBorrowState[cToken].index == 0 && compBorrowState[cToken].block == 0) {\n compBorrowState[cToken] = CompMarketState({\n index: compInitialIndex,\n block: safe32(getBlockNumber(), \"block number exceeds 32 bits\")\n });\n }\n }\n\n /**\n * @notice Remove a market from compMarkets, preventing it from earning COMP in the flywheel\n * @param cToken The address of the market to drop\n */\n function _dropCompMarket(address cToken) public {\n require(msg.sender == admin, \"only admin can drop comp market\");\n\n Market storage market = markets[cToken];\n require(market.isComped == true, \"market is not a comp market\");\n\n market.isComped = false;\n emit MarketComped(CToken(cToken), false);\n\n refreshCompSpeeds();\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return The list of market addresses\n */\n function getAllMarkets() public view returns (CToken[] memory) {\n return allMarkets;\n }\n\n function getBlockNumber() public view returns (uint) {\n return block.number;\n }\n\n /**\n * @notice Return the address of the COMP token\n * @return The address of COMP\n */\n function getCompAddress() public view returns (address) {\n return 0xc00e94Cb662C3520282E6f5717214004A7f26888;\n }\n}\n" + }, + "contracts/SimplePriceOracle.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./PriceOracle.sol\";\nimport \"./CErc20.sol\";\n\ncontract SimplePriceOracle is PriceOracle {\n mapping(address => uint) prices;\n event PricePosted(address asset, uint previousPriceMantissa, uint requestedPriceMantissa, uint newPriceMantissa);\n\n function getUnderlyingPrice(CToken cToken) public view returns (uint) {\n if (compareStrings(cToken.symbol(), \"cETH\")) {\n return 1e18;\n } else {\n return prices[address(CErc20(address(cToken)).underlying())];\n }\n }\n\n function setUnderlyingPrice(CToken cToken, uint underlyingPriceMantissa) public {\n address asset = address(CErc20(address(cToken)).underlying());\n emit PricePosted(asset, prices[asset], underlyingPriceMantissa, underlyingPriceMantissa);\n prices[asset] = underlyingPriceMantissa;\n }\n\n function setDirectPrice(address asset, uint price) public {\n emit PricePosted(asset, prices[asset], price, price);\n prices[asset] = price;\n }\n\n // v1 price oracle interface for use as backing of proxy\n function assetPrices(address asset) external view returns (uint) {\n return prices[asset];\n }\n\n function compareStrings(string memory a, string memory b) internal pure returns (bool) {\n return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));\n }\n}\n" + }, + "contracts/CErc20.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\n\n/**\n * @title Compound's CErc20 Contract\n * @notice CTokens which wrap an EIP-20 underlying\n * @author Compound\n */\ncontract CErc20 is CToken, CErc20Interface {\n /**\n * @notice Initialize the new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n */\n function initialize(address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_) public {\n // CToken initialize does the bulk of the work\n super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);\n\n // Set underlying and sanity check it\n underlying = underlying_;\n EIP20Interface(underlying).totalSupply();\n }\n\n /*** User Interface ***/\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function mint(uint mintAmount) external returns (uint) {\n (uint err,) = mintInternal(mintAmount);\n return err;\n }\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 a failure (see ErrorReporter.sol for details)\n */\n function redeem(uint redeemTokens) external returns (uint) {\n return redeemInternal(redeemTokens);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to redeem\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\n return redeemUnderlyingInternal(redeemAmount);\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function borrow(uint borrowAmount) external returns (uint) {\n return borrowInternal(borrowAmount);\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function repayBorrow(uint repayAmount) external returns (uint) {\n (uint err,) = repayBorrowInternal(repayAmount);\n return err;\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) {\n (uint err,) = repayBorrowBehalfInternal(borrower, repayAmount);\n return err;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this cToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param cTokenCollateral The market in which to seize collateral from the borrower\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint) {\n (uint err,) = liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);\n return err;\n }\n\n /**\n * @notice The sender adds to reserves.\n * @param addAmount The amount fo underlying token to add as reserves\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _addReserves(uint addAmount) external returns (uint) {\n return _addReservesInternal(addAmount);\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function getCashPrior() internal view returns (uint) {\n EIP20Interface token = EIP20Interface(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.\n * This will revert due to insufficient balance or insufficient allowance.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n *\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\n function doTransferIn(address from, uint amount) internal returns (uint) {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));\n token.transferFrom(from, address(this), amount);\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 { // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 { // This is a compliant ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default { // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"TOKEN_TRANSFER_IN_FAILED\");\n\n // Calculate the amount that was *actually* transferred\n uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));\n require(balanceAfter >= balanceBefore, \"TOKEN_TRANSFER_IN_OVERFLOW\");\n return balanceAfter - balanceBefore; // underflow already checked above, just subtract\n }\n\n /**\n * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory\n * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to\n * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified\n * it is >= amount, this should not revert in normal conditions.\n *\n * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.\n * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\n function doTransferOut(address payable to, uint amount) internal {\n EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n token.transfer(to, amount);\n\n bool success;\n assembly {\n switch returndatasize()\n case 0 { // This is a non-standard ERC-20\n success := not(0) // set success to true\n }\n case 32 { // This is a complaint ERC-20\n returndatacopy(0, 0, 32)\n success := mload(0) // Set `success = returndata` of external call\n }\n default { // This is an excessively non-compliant ERC-20, revert.\n revert(0, 0)\n }\n }\n require(success, \"TOKEN_TRANSFER_OUT_FAILED\");\n }\n}\n" + }, + "contracts/Fed.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\nimport \"./CErc20.sol\";\nimport \"./ERC20.sol\";\nimport \"./Exponential.sol\";\n\ncontract Fed {\n using SafeMath for uint;\n\n CErc20 public ctoken;\n ERC20 public underlying;\n address public chair; // Fed Chair\n address public gov;\n uint public supply;\n\n event Expansion(uint amount);\n event Contraction(uint amount);\n\n constructor(CErc20 ctoken_, address gov_) public {\n ctoken = ctoken_;\n underlying = ERC20(ctoken_.underlying());\n underlying.approve(address(ctoken), uint(-1));\n chair = msg.sender;\n gov = gov_;\n }\n\n function changeGov(address newGov_) public {\n require(msg.sender == gov, \"ONLY GOV\");\n gov = newGov_;\n }\n\n function changeChair(address newChair_) public {\n require(msg.sender == gov, \"ONLY GOV\");\n chair = newChair_;\n }\n\n function resign() public {\n require(msg.sender == chair, \"ONLY CHAIR\");\n chair = address(0);\n }\n\n function expansion(uint amount) public {\n require(msg.sender == chair, \"ONLY CHAIR\");\n underlying.mint(address(this), amount);\n require(ctoken.mint(amount) == 0, 'Supplying failed');\n supply = supply.add(amount);\n emit Expansion(amount);\n }\n\n function contraction(uint amount) public {\n require(msg.sender == chair, \"ONLY CHAIR\");\n require(amount <= supply, \"AMOUNT TOO BIG\"); // can't burn profits\n require(ctoken.redeemUnderlying(amount) == 0, \"Redeem failed\");\n underlying.burn(amount);\n supply = supply.sub(amount);\n emit Contraction(amount);\n }\n\n function takeProfit() public {\n uint underlyingBalance = ctoken.balanceOfUnderlying(address(this));\n uint profit = underlyingBalance.sub(supply);\n if(profit > 0) {\n require(ctoken.redeemUnderlying(profit) == 0, \"Redeem failed\");\n underlying.transfer(gov, profit);\n }\n }\n \n}" + }, + "contracts/ERC20.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\n\ncontract ERC20 {\n using SafeMath for uint;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint public totalSupply;\n address public operator;\n address public pendingOperator;\n mapping(address => uint) public balanceOf;\n mapping(address => mapping(address => uint)) public allowance;\n mapping (address => bool) public minters;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint value);\n event Transfer(address indexed from, address indexed to, uint value);\n event AddMinter(address indexed minter);\n event RemoveMinter(address indexed minter);\n event ChangeOperator(address indexed newOperator);\n\n modifier onlyOperator {\n require(msg.sender == operator, \"ONLY OPERATOR\");\n _;\n }\n\n constructor(string memory name_, string memory symbol_, uint8 decimals_) public {\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n operator = msg.sender;\n uint chainId;\n assembly {\n chainId := chainid\n }\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n keccak256(bytes(name)),\n keccak256(bytes('1')),\n chainId,\n address(this)\n )\n );\n }\n\n function setPendingOperator(address newOperator_) public onlyOperator {\n pendingOperator = newOperator_;\n }\n\n function claimOperator() public {\n require(msg.sender == pendingOperator, \"ONLY PENDING OPERATOR\");\n operator = pendingOperator;\n pendingOperator = address(0);\n emit ChangeOperator(operator);\n }\n\n function addMinter(address minter_) public onlyOperator {\n minters[minter_] = true;\n emit AddMinter(minter_);\n }\n\n function removeMinter(address minter_) public onlyOperator {\n minters[minter_] = false;\n emit RemoveMinter(minter_);\n }\n\n function mint(address to, uint amount) public {\n require(minters[msg.sender] == true || msg.sender == operator, \"ONLY MINTERS OR OPERATOR\");\n _mint(to, amount);\n }\n\n function burn(uint amount) public {\n _burn(msg.sender, amount);\n }\n\n function _mint(address to, uint value) internal {\n totalSupply = totalSupply.add(value);\n balanceOf[to] = balanceOf[to].add(value);\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint value) internal {\n balanceOf[from] = balanceOf[from].sub(value);\n totalSupply = totalSupply.sub(value);\n emit Transfer(from, address(0), value);\n }\n\n function _approve(address owner, address spender, uint value) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(address from, address to, uint value) private {\n balanceOf[from] = balanceOf[from].sub(value);\n balanceOf[to] = balanceOf[to].add(value);\n emit Transfer(from, to, value);\n }\n\n function approve(address spender, uint value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(address from, address to, uint value) external returns (bool) {\n if (allowance[from][msg.sender] != uint(-1)) {\n allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {\n require(deadline >= block.timestamp, 'EXPIRED');\n bytes32 digest = keccak256(\n abi.encodePacked(\n '\\x19\\x01',\n DOMAIN_SEPARATOR,\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n )\n );\n address recoveredAddress = ecrecover(digest, v, r, s);\n require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');\n _approve(owner, spender, value);\n }\n}" + }, + "contracts/LpFeed.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./Exponential.sol\";\n\ninterface IUniswapV2Pair {\n\n function totalSupply() external view returns (uint);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n}\n\ninterface Feed {\n function decimals() external view returns (uint8);\n function latestAnswer() external view returns (uint);\n}\n\ncontract LpFeed is Feed, Exponential {\n\n IUniswapV2Pair public pair;\n Feed public feed0;\n Feed public feed1;\n uint8 public constant decimals = 18;\n\n constructor (IUniswapV2Pair _pair, Feed _feed0, Feed _feed1) public {\n require(_feed0.decimals() <= 18, \"INVALID FEED 0 DECIMALS\");\n require(_feed1.decimals() <= 18, \"INVALID FEED 1 DECIMALS\");\n pair = _pair;\n feed0 = _feed0;\n feed1 = _feed1;\n }\n\n function latestAnswer() public view returns (uint) {\n uint totalSupply = pair.totalSupply();\n (uint r0, uint r1, ) = pair.getReserves();\n uint sqrtR = sqrt(mul_(r0, r1));\n uint p0 = feed0.decimals() == 18? feed0.latestAnswer(): feed0.latestAnswer() * 10 ** (18 - uint(feed0.decimals()));\n uint p1 = feed1.decimals() == 18? feed1.latestAnswer(): feed1.latestAnswer() * 10 ** (18 - uint(feed1.decimals()));\n uint sqrtP = sqrt(mul_(p0, p1));\n return div_(mul_(2, mul_(sqrtR, sqrtP)), totalSupply);\n }\n\n function sqrt(uint x) pure internal returns (uint) {\n if (x == 0) return 0;\n uint xx = x;\n uint r = 1;\n\n if (xx >= 0x100000000000000000000000000000000) {\n xx >>= 128;\n r <<= 64;\n }\n if (xx >= 0x10000000000000000) {\n xx >>= 64;\n r <<= 32;\n }\n if (xx >= 0x100000000) {\n xx >>= 32;\n r <<= 16;\n }\n if (xx >= 0x10000) {\n xx >>= 16;\n r <<= 8;\n }\n if (xx >= 0x100) {\n xx >>= 8;\n r <<= 4;\n }\n if (xx >= 0x10) {\n xx >>= 4;\n r <<= 2;\n }\n if (xx >= 0x8) {\n r <<= 1;\n }\n\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1;\n r = (r + x / r) >> 1; // Seven iterations should be enough\n uint r1 = x / r;\n return (r < r1 ? r : r1);\n }\n}" + }, + "contracts/ComptrollerG2.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n */\ncontract ComptrollerG2 is ComptrollerV2Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {\n /**\n * @notice Emitted when an admin supports a market\n */\n event MarketListed(CToken cToken);\n\n /**\n * @notice Emitted when an account enters a market\n */\n event MarketEntered(CToken cToken, address account);\n\n /**\n * @notice Emitted when an account exits a market\n */\n event MarketExited(CToken cToken, address account);\n\n /**\n * @notice Emitted when close factor is changed by admin\n */\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /**\n * @notice Emitted when a collateral factor is changed by admin\n */\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /**\n * @notice Emitted when liquidation incentive is changed by admin\n */\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /**\n * @notice Emitted when maxAssets is changed by admin\n */\n event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);\n\n /**\n * @notice Emitted when price oracle is changed\n */\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n /**\n * @notice Emitted when pause guardian is changed\n */\n event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);\n\n /**\n * @notice Emitted when an action is paused globally\n */\n event ActionPaused(string action, bool pauseState);\n\n /**\n * @notice Emitted when an action is paused on a market\n */\n event ActionPaused(CToken cToken, string action, bool pauseState);\n\n // closeFactorMantissa must be strictly greater than this value\n uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n\n results[i] = uint(addToMarketInternal(cToken, msg.sender));\n }\n\n return results;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param cToken The market to enter\n * @param borrower The address of the account to modify\n * @return Success indicator for whether the market was entered\n */\n function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // market is not listed, cannot join\n return Error.MARKET_NOT_LISTED;\n }\n\n if (marketToJoin.accountMembership[borrower] == true) {\n // already joined\n return Error.NO_ERROR;\n }\n\n if (accountAssets[borrower].length >= maxAssets) {\n // no space, cannot join\n return Error.TOO_MANY_ASSETS;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(cToken);\n\n emit MarketEntered(cToken, borrower);\n\n return Error.NO_ERROR;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing neccessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!mintGuardianPaused[cToken], \"mint is paused\");\n\n // Shh - currently unused\n minter;\n mintAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param actualMintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint actualMintAmount, uint mintTokens) external {\n // Shh - currently unused\n cToken;\n minter;\n actualMintAmount;\n mintTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n return redeemAllowedInternal(cToken, redeemer, redeemTokens);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n // Shh - currently unused\n cToken;\n redeemer;\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!borrowGuardianPaused[cToken], \"borrow is paused\");\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n if (!markets[cToken].accountMembership[borrower]) {\n // only cTokens may call borrowAllowed if borrower not in market\n require(msg.sender == cToken, \"sender must be cToken\");\n\n // attempt to add borrower to the market\n Error err = addToMarketInternal(CToken(msg.sender), borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n\n // it should be impossible to break the important invariant\n assert(markets[cToken].accountMembership[borrower]);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n // Shh - currently unused\n cToken;\n borrower;\n borrowAmount;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n payer;\n borrower;\n repayAmount;\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint actualRepayAmount,\n uint borrowerIndex) external {\n // Shh - currently unused\n cToken;\n payer;\n borrower;\n actualRepayAmount;\n borrowerIndex;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n // Shh - currently unused\n liquidator;\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (mathErr != MathError.NO_ERROR) {\n return uint(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param actualRepayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint actualRepayAmount,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenBorrowed;\n cTokenCollateral;\n liquidator;\n borrower;\n actualRepayAmount;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!seizeGuardianPaused, \"seize is paused\");\n\n // Shh - currently unused\n liquidator;\n borrower;\n seizeTokens;\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n // Shh - currently unused\n cTokenCollateral;\n cTokenBorrowed;\n liquidator;\n borrower;\n seizeTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n // Pausing is a very serious situation - we revert to sound the alarms\n require(!transferGuardianPaused, \"transfer is paused\");\n\n // Shh - currently unused\n dst;\n\n // *may include Policy Hook-type checks\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n return redeemAllowedInternal(cToken, src, transferTokens);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n // Shh - currently unused\n cToken;\n src;\n dst;\n transferTokens;\n\n // Shh - we don't ever want this hook to be marked pure\n if (false) {\n maxAssets = maxAssets;\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToEther;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return (possible error code (semi-opaque),\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address cTokenModify,\n uint redeemTokens,\n uint borrowAmount) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount);\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n (mErr, vars.tokensToEther) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToEther * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToEther, vars.cTokenBalance, vars.sumCollateral);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToEther * redeemTokens\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToEther, redeemTokens, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, actualRepayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets maxAssets which controls how many markets can be entered\n * @dev Admin function to set maxAssets\n * @param newMaxAssets New max assets\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setMaxAssets(uint newMaxAssets) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);\n }\n\n uint oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Check de-scaled min <= newLiquidationIncentive <= max\n Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa});\n Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa});\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa});\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, isComped: false, collateralFactorMantissa: 0});\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Admin function to change the Pause Guardian\n * @param newPauseGuardian The address of the new Pause Guardian\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _setPauseGuardian(address newPauseGuardian) public returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);\n }\n\n // Save current value for inclusion in log\n address oldPauseGuardian = pauseGuardian;\n\n // Store pauseGuardian with value newPauseGuardian\n pauseGuardian = newPauseGuardian;\n\n // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)\n emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);\n\n return uint(Error.NO_ERROR);\n }\n\n function _setMintPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n mintGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Mint\", state);\n return state;\n }\n\n function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {\n require(markets[address(cToken)].isListed, \"cannot pause a market that is not listed\");\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n borrowGuardianPaused[address(cToken)] = state;\n emit ActionPaused(cToken, \"Borrow\", state);\n return state;\n }\n\n function _setTransferPaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n transferGuardianPaused = state;\n emit ActionPaused(\"Transfer\", state);\n return state;\n }\n\n function _setSeizePaused(bool state) public returns (bool) {\n require(msg.sender == pauseGuardian || msg.sender == admin, \"only pause guardian and admin can pause\");\n require(msg.sender == admin || state == true, \"only admin can unpause\");\n\n seizeGuardianPaused = state;\n emit ActionPaused(\"Seize\", state);\n return state;\n }\n\n function _become(Unitroller unitroller) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n\n uint changeStatus = unitroller._acceptImplementation();\n require(changeStatus == 0, \"change not authorized\");\n }\n}\n" + }, + "contracts/ComptrollerG1.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./PriceOracle.sol\";\nimport \"./ComptrollerInterface.sol\";\nimport \"./ComptrollerStorage.sol\";\nimport \"./Unitroller.sol\";\n\n/**\n * @title Compound's Comptroller Contract\n * @author Compound\n * @dev This was the first version of the Comptroller brains.\n * We keep it so our tests can continue to do the real-life behavior of upgrading from this logic forward.\n */\ncontract ComptrollerG1 is ComptrollerV1Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential {\n struct Market {\n /**\n * @notice Whether or not this market is listed\n */\n bool isListed;\n\n /**\n * @notice Multiplier representing the most one can borrow against their collateral in this market.\n * For instance, 0.9 to allow borrowing 90% of collateral value.\n * Must be between 0 and 1, and stored as a mantissa.\n */\n uint collateralFactorMantissa;\n\n /**\n * @notice Per-market mapping of \"accounts in this asset\"\n */\n mapping(address => bool) accountMembership;\n }\n\n /**\n * @notice Official mapping of cTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n /**\n * @notice Emitted when an admin supports a market\n */\n event MarketListed(CToken cToken);\n\n /**\n * @notice Emitted when an account enters a market\n */\n event MarketEntered(CToken cToken, address account);\n\n /**\n * @notice Emitted when an account exits a market\n */\n event MarketExited(CToken cToken, address account);\n\n /**\n * @notice Emitted when close factor is changed by admin\n */\n event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);\n\n /**\n * @notice Emitted when a collateral factor is changed by admin\n */\n event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);\n\n /**\n * @notice Emitted when liquidation incentive is changed by admin\n */\n event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);\n\n /**\n * @notice Emitted when maxAssets is changed by admin\n */\n event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets);\n\n /**\n * @notice Emitted when price oracle is changed\n */\n event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);\n\n // closeFactorMantissa must be strictly greater than this value\n uint constant closeFactorMinMantissa = 5e16; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint constant closeFactorMaxMantissa = 9e17; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint constant collateralFactorMaxMantissa = 9e17; // 0.9\n\n // liquidationIncentiveMantissa must be no less than this value\n uint constant liquidationIncentiveMinMantissa = mantissaOne;\n\n // liquidationIncentiveMantissa must be no greater than this value\n uint constant liquidationIncentiveMaxMantissa = 15e17; // 1.5\n\n constructor() public {\n admin = msg.sender;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A dynamic list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (CToken[] memory) {\n CToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in the given asset\n * @param account The address of the account to check\n * @param cToken The cToken to check\n * @return True if the account is in the asset, otherwise false.\n */\n function checkMembership(address account, CToken cToken) external view returns (bool) {\n return markets[address(cToken)].accountMembership[account];\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation\n * @param cTokens The list of addresses of the cToken markets to be enabled\n * @return Success indicator for whether each corresponding market was entered\n */\n function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {\n uint len = cTokens.length;\n\n uint[] memory results = new uint[](len);\n for (uint i = 0; i < len; i++) {\n CToken cToken = CToken(cTokens[i]);\n Market storage marketToJoin = markets[address(cToken)];\n\n if (!marketToJoin.isListed) {\n // if market is not listed, cannot join move along\n results[i] = uint(Error.MARKET_NOT_LISTED);\n continue;\n }\n\n if (marketToJoin.accountMembership[msg.sender] == true) {\n // if already joined, move along\n results[i] = uint(Error.NO_ERROR);\n continue;\n }\n\n if (accountAssets[msg.sender].length >= maxAssets) {\n // if no space, cannot join, move along\n results[i] = uint(Error.TOO_MANY_ASSETS);\n continue;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[msg.sender] = true;\n accountAssets[msg.sender].push(cToken);\n\n emit MarketEntered(cToken, msg.sender);\n\n results[i] = uint(Error.NO_ERROR);\n }\n\n return results;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing neccessary collateral for an outstanding borrow.\n * @param cTokenAddress The address of the asset to be removed\n * @return Whether or not the account successfully exited the market\n */\n function exitMarket(address cTokenAddress) external returns (uint) {\n CToken cToken = CToken(cTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the cToken */\n (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);\n require(oErr == 0, \"exitMarket: getAccountSnapshot failed\"); // semi-opaque error code\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);\n if (allowed != 0) {\n return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);\n }\n\n Market storage marketToExit = markets[address(cToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Set cToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete cToken from the account’s list of assets */\n // load into memory for faster iteration\n CToken[] memory userAssetList = accountAssets[msg.sender];\n uint len = userAssetList.length;\n uint assetIndex = len;\n for (uint i = 0; i < len; i++) {\n if (userAssetList[i] == cToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n CToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.length--;\n\n emit MarketExited(cToken, msg.sender);\n\n return uint(Error.NO_ERROR);\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param cToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) {\n minter; // currently unused\n mintAmount; // currently unused\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates mint and reverts on rejection. May emit logs.\n * @param cToken Asset being minted\n * @param minter The address minting the tokens\n * @param mintAmount The amount of the underlying asset being minted\n * @param mintTokens The number of tokens being minted\n */\n function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external {\n cToken; // currently unused\n minter; // currently unused\n mintAmount; // currently unused\n mintTokens; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param cToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market\n * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) {\n return redeemAllowedInternal(cToken, redeemer, redeemTokens);\n }\n\n function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!markets[cToken].accountMembership[redeemer]) {\n return uint(Error.NO_ERROR);\n }\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates redeem and reverts on rejection. May emit logs.\n * @param cToken Asset being redeemed\n * @param redeemer The address redeeming the tokens\n * @param redeemAmount The amount of the underlying asset being redeemed\n * @param redeemTokens The number of tokens being redeemed\n */\n function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {\n cToken; // currently unused\n redeemer; // currently unused\n redeemAmount; // currently unused\n redeemTokens; // currently unused\n\n // Require tokens is zero or amount is also zero\n if (redeemTokens == 0 && redeemAmount > 0) {\n revert(\"redeemTokens zero\");\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param cToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) {\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n if (!markets[cToken].accountMembership[borrower]) {\n return uint(Error.MARKET_NOT_ENTERED);\n }\n\n if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {\n return uint(Error.PRICE_ERROR);\n }\n\n (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall > 0) {\n return uint(Error.INSUFFICIENT_LIQUIDITY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates borrow and reverts on rejection. May emit logs.\n * @param cToken Asset whose underlying is being borrowed\n * @param borrower The address borrowing the underlying\n * @param borrowAmount The amount of the underlying asset requested to borrow\n */\n function borrowVerify(address cToken, address borrower, uint borrowAmount) external {\n cToken; // currently unused\n borrower; // currently unused\n borrowAmount; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param cToken The market to verify the repay against\n * @param payer The account which would repay the asset\n * @param borrower The account which would borrowed the asset\n * @param repayAmount The amount of the underlying asset the account would repay\n * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function repayBorrowAllowed(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount) external returns (uint) {\n payer; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n\n if (!markets[cToken].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates repayBorrow and reverts on rejection. May emit logs.\n * @param cToken Asset being repaid\n * @param payer The address repaying the borrow\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function repayBorrowVerify(\n address cToken,\n address payer,\n address borrower,\n uint repayAmount,\n uint borrowerIndex) external {\n cToken; // currently unused\n payer; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n borrowerIndex; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowAllowed(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount) external returns (uint) {\n liquidator; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n\n if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n // *may include Policy Hook-type checks\n\n /* The borrower must have shortfall in order to be liquidatable */\n (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower);\n if (err != Error.NO_ERROR) {\n return uint(err);\n }\n if (shortfall == 0) {\n return uint(Error.INSUFFICIENT_SHORTFALL);\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower);\n (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);\n if (mathErr != MathError.NO_ERROR) {\n return uint(Error.MATH_ERROR);\n }\n if (repayAmount > maxClose) {\n return uint(Error.TOO_MUCH_REPAY);\n }\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n */\n function liquidateBorrowVerify(\n address cTokenBorrowed,\n address cTokenCollateral,\n address liquidator,\n address borrower,\n uint repayAmount,\n uint seizeTokens) external {\n cTokenBorrowed; // currently unused\n cTokenCollateral; // currently unused\n liquidator; // currently unused\n borrower; // currently unused\n repayAmount; // currently unused\n seizeTokens; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeAllowed(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external returns (uint) {\n liquidator; // currently unused\n borrower; // currently unused\n seizeTokens; // currently unused\n\n if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) {\n return uint(Error.MARKET_NOT_LISTED);\n }\n\n if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) {\n return uint(Error.COMPTROLLER_MISMATCH);\n }\n\n // *may include Policy Hook-type checks\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Validates seize and reverts on rejection. May emit logs.\n * @param cTokenCollateral Asset which was used as collateral and will be seized\n * @param cTokenBorrowed Asset which was borrowed by the borrower\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @param seizeTokens The number of collateral tokens to seize\n */\n function seizeVerify(\n address cTokenCollateral,\n address cTokenBorrowed,\n address liquidator,\n address borrower,\n uint seizeTokens) external {\n cTokenCollateral; // currently unused\n cTokenBorrowed; // currently unused\n liquidator; // currently unused\n borrower; // currently unused\n seizeTokens; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param cToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)\n */\n function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) {\n cToken; // currently unused\n src; // currently unused\n dst; // currently unused\n transferTokens; // currently unused\n\n // *may include Policy Hook-type checks\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n return redeemAllowedInternal(cToken, src, transferTokens);\n }\n\n /**\n * @notice Validates transfer and reverts on rejection. May emit logs.\n * @param cToken Asset being transferred\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of cTokens to transfer\n */\n function transferVerify(address cToken, address src, address dst, uint transferTokens) external {\n cToken; // currently unused\n src; // currently unused\n dst; // currently unused\n transferTokens; // currently unused\n\n if (false) {\n maxAssets = maxAssets; // not pure\n }\n }\n\n /*** Liquidity/Liquidation Calculations ***/\n\n /**\n * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.\n * Note that `cTokenBalance` is the number of cTokens the account owns in the market,\n * whereas `borrowBalance` is the amount of underlying that the account has borrowed.\n */\n struct AccountLiquidityLocalVars {\n uint sumCollateral;\n uint sumBorrowPlusEffects;\n uint cTokenBalance;\n uint borrowBalance;\n uint exchangeRateMantissa;\n uint oraclePriceMantissa;\n Exp collateralFactor;\n Exp exchangeRate;\n Exp oraclePrice;\n Exp tokensToEther;\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code (semi-opaque),\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidity(address account) public view returns (uint, uint, uint) {\n (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n\n return (uint(err), liquidity, shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity wrt collateral requirements\n * @return (possible error code,\n account liquidity in excess of collateral requirements,\n * account shortfall below collateral requirements)\n */\n function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {\n return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @param cTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data,\n * without calculating accumulated interest.\n * @return (possible error code,\n hypothetical account liquidity in excess of collateral requirements,\n * hypothetical account shortfall below collateral requirements)\n */\n function getHypotheticalAccountLiquidityInternal(\n address account,\n CToken cTokenModify,\n uint redeemTokens,\n uint borrowAmount) internal view returns (Error, uint, uint) {\n\n AccountLiquidityLocalVars memory vars; // Holds all our calculation results\n uint oErr;\n MathError mErr;\n\n // For each asset the account is in\n CToken[] memory assets = accountAssets[account];\n for (uint i = 0; i < assets.length; i++) {\n CToken asset = assets[i];\n\n // Read the balances and exchange rate from the cToken\n (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);\n if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades\n return (Error.SNAPSHOT_ERROR, 0, 0);\n }\n vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});\n vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});\n\n // Get the normalized price of the asset\n vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);\n if (vars.oraclePriceMantissa == 0) {\n return (Error.PRICE_ERROR, 0, 0);\n }\n vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});\n\n // Pre-compute a conversion factor from tokens -> ether (normalized price value)\n (mErr, vars.tokensToEther) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumCollateral += tokensToEther * cTokenBalance\n (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToEther, vars.cTokenBalance, vars.sumCollateral);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // sumBorrowPlusEffects += oraclePrice * borrowBalance\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // Calculate effects of interacting with cTokenModify\n if (asset == cTokenModify) {\n // redeem effect\n // sumBorrowPlusEffects += tokensToEther * redeemTokens\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToEther, redeemTokens, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n\n // borrow effect\n // sumBorrowPlusEffects += oraclePrice * borrowAmount\n (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);\n if (mErr != MathError.NO_ERROR) {\n return (Error.MATH_ERROR, 0, 0);\n }\n }\n }\n\n // These are safe, as the underflow condition is checked first\n if (vars.sumCollateral > vars.sumBorrowPlusEffects) {\n return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);\n } else {\n return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);\n }\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in cToken.liquidateBorrowFresh)\n * @param cTokenBorrowed The address of the borrowed cToken\n * @param cTokenCollateral The address of the collateral cToken\n * @param repayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens\n * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation)\n */\n function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint repayAmount) external view returns (uint, uint) {\n /* Read oracle prices for borrowed and collateral markets */\n uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed));\n uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral));\n if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {\n return (uint(Error.PRICE_ERROR), 0);\n }\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = repayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = repayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n MathError mathErr;\n\n (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, ratio) = divExp(numerator, denominator);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n (mathErr, seizeTokens) = mulScalarTruncate(ratio, repayAmount);\n if (mathErr != MathError.NO_ERROR) {\n return (uint(Error.MATH_ERROR), 0);\n }\n\n return (uint(Error.NO_ERROR), seizeTokens);\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Sets a new price oracle for the comptroller\n * @dev Admin function to set a new price oracle\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPriceOracle(PriceOracle newOracle) public returns (uint) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);\n }\n\n // Track the old oracle for the comptroller\n PriceOracle oldOracle = oracle;\n\n // Ensure invoke newOracle.isPriceOracle() returns true\n // require(newOracle.isPriceOracle(), \"oracle method isPriceOracle returned false\");\n\n // Set comptroller's oracle to newOracle\n oracle = newOracle;\n\n // Emit NewPriceOracle(oldOracle, newOracle)\n emit NewPriceOracle(oldOracle, newOracle);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the closeFactor used when liquidating borrows\n * @dev Admin function to set closeFactor\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint256) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK);\n }\n\n Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa});\n Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa});\n if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa});\n if (lessThanExp(highLimit, newCloseFactorExp)) {\n return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION);\n }\n\n uint oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev Admin function to set per-market collateralFactor\n * @param cToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint256) {\n // Check caller is admin\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);\n }\n\n // Verify market is listed\n Market storage market = markets[address(cToken)];\n if (!market.isListed) {\n return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);\n }\n\n Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});\n\n // Check collateral factor <= 0.9\n Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});\n if (lessThanExp(highLimit, newCollateralFactorExp)) {\n return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) {\n return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);\n }\n\n // Set market's collateral factor to new collateral factor, remember old value\n uint oldCollateralFactorMantissa = market.collateralFactorMantissa;\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n\n // Emit event with asset, old collateral factor, and new collateral factor\n emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets maxAssets which controls how many markets can be entered\n * @dev Admin function to set maxAssets\n * @param newMaxAssets New max assets\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setMaxAssets(uint newMaxAssets) external returns (uint) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK);\n }\n\n uint oldMaxAssets = maxAssets;\n maxAssets = newMaxAssets;\n emit NewMaxAssets(oldMaxAssets, newMaxAssets);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev Admin function to set liquidationIncentive\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)\n */\n function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {\n // Check caller is admin OR currently initialzing as new unitroller implementation\n if (!adminOrInitializing()) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);\n }\n\n // Check de-scaled 1 <= newLiquidationDiscount <= 1.5\n Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa});\n Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa});\n if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa});\n if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) {\n return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION);\n }\n\n // Save current value for use in log\n uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n\n return uint(Error.NO_ERROR);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Admin function to set isListed and add support for the market\n * @param cToken The address of the market (token) to list\n * @return uint 0=success, otherwise a failure. (See enum Error for details)\n */\n function _supportMarket(CToken cToken) external returns (uint) {\n if (msg.sender != admin) {\n return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);\n }\n\n if (markets[address(cToken)].isListed) {\n return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);\n }\n\n cToken.isCToken(); // Sanity check to make sure its really a CToken\n\n markets[address(cToken)] = Market({isListed: true, collateralFactorMantissa: 0});\n emit MarketListed(cToken);\n\n return uint(Error.NO_ERROR);\n }\n\n function _become(Unitroller unitroller, PriceOracle _oracle, uint _closeFactorMantissa, uint _maxAssets, bool reinitializing) public {\n require(msg.sender == unitroller.admin(), \"only unitroller admin can change brains\");\n uint changeStatus = unitroller._acceptImplementation();\n\n require(changeStatus == 0, \"change not authorized\");\n\n if (!reinitializing) {\n ComptrollerG1 freshBrainedComptroller = ComptrollerG1(address(unitroller));\n\n // Ensure invoke _setPriceOracle() = 0\n uint err = freshBrainedComptroller._setPriceOracle(_oracle);\n require (err == uint(Error.NO_ERROR), \"set price oracle error\");\n\n // Ensure invoke _setCloseFactor() = 0\n err = freshBrainedComptroller._setCloseFactor(_closeFactorMantissa);\n require (err == uint(Error.NO_ERROR), \"set close factor error\");\n\n // Ensure invoke _setMaxAssets() = 0\n err = freshBrainedComptroller._setMaxAssets(_maxAssets);\n require (err == uint(Error.NO_ERROR), \"set max asssets error\");\n\n // Ensure invoke _setLiquidationIncentive(liquidationIncentiveMinMantissa) = 0\n err = freshBrainedComptroller._setLiquidationIncentive(liquidationIncentiveMinMantissa);\n require (err == uint(Error.NO_ERROR), \"set liquidation incentive error\");\n }\n }\n\n /**\n * @dev Check that caller is admin or this contract is initializing itself as\n * the new implementation.\n * There should be no way to satisfy msg.sender == comptrollerImplementaiton\n * without tx.origin also being admin, but both are included for extra safety\n */\n function adminOrInitializing() internal view returns (bool) {\n bool initializing = (\n msg.sender == comptrollerImplementation\n &&\n //solium-disable-next-line security/no-tx-origin\n tx.origin == admin\n );\n bool isAdmin = msg.sender == admin;\n return isAdmin || initializing;\n }\n}" + }, + "contracts/CEther.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CToken.sol\";\n\n/**\n * @title Compound's CEther Contract\n * @notice CToken which wraps Ether\n * @author Compound\n */\ncontract CEther is CToken {\n /**\n * @notice Construct a new CEther money market\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n */\n constructor(ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_) public {\n // Creator of the contract is admin during initialization\n admin = msg.sender;\n\n initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n }\n\n\n /*** User Interface ***/\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @dev Reverts upon any failure\n */\n function mint() external payable {\n (uint err,) = mintInternal(msg.value);\n requireNoError(err, \"mint failed\");\n }\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 a failure (see ErrorReporter.sol for details)\n */\n function redeem(uint redeemTokens) external returns (uint) {\n return redeemInternal(redeemTokens);\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to redeem\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\n return redeemUnderlyingInternal(redeemAmount);\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function borrow(uint borrowAmount) external returns (uint) {\n return borrowInternal(borrowAmount);\n }\n\n /**\n * @notice Sender repays their own borrow\n * @dev Reverts upon any failure\n */\n function repayBorrow() external payable {\n (uint err,) = repayBorrowInternal(msg.value);\n requireNoError(err, \"repayBorrow failed\");\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @dev Reverts upon any failure\n * @param borrower the account with the debt being payed off\n */\n function repayBorrowBehalf(address borrower) external payable {\n (uint err,) = repayBorrowBehalfInternal(borrower, msg.value);\n requireNoError(err, \"repayBorrowBehalf failed\");\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @dev Reverts upon any failure\n * @param borrower The borrower of this cToken to be liquidated\n * @param cTokenCollateral The market in which to seize collateral from the borrower\n */\n function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable {\n (uint err,) = liquidateBorrowInternal(borrower, msg.value, cTokenCollateral);\n requireNoError(err, \"liquidateBorrow failed\");\n }\n\n /**\n * @notice Send Ether to CEther to mint\n */\n function () external payable {\n (uint err,) = mintInternal(msg.value);\n requireNoError(err, \"mint failed\");\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of Ether, before this message\n * @dev This excludes the value of the current message, if any\n * @return The quantity of Ether owned by this contract\n */\n function getCashPrior() internal view returns (uint) {\n (MathError err, uint startingBalance) = subUInt(address(this).balance, msg.value);\n require(err == MathError.NO_ERROR);\n return startingBalance;\n }\n\n /**\n * @notice Perform the actual transfer in, which is a no-op\n * @param from Address sending the Ether\n * @param amount Amount of Ether being sent\n * @return The actual amount of Ether transferred\n */\n function doTransferIn(address from, uint amount) internal returns (uint) {\n // Sanity checks\n require(msg.sender == from, \"sender mismatch\");\n require(msg.value == amount, \"value mismatch\");\n return amount;\n }\n\n function doTransferOut(address payable to, uint amount) internal {\n /* Send the Ether, with minimal gas and revert on failure */\n to.transfer(amount);\n }\n\n function requireNoError(uint errCode, string memory message) internal pure {\n if (errCode == uint(Error.NO_ERROR)) {\n return;\n }\n\n bytes memory fullMessage = new bytes(bytes(message).length + 5);\n uint i;\n\n for (i = 0; i < bytes(message).length; i++) {\n fullMessage[i] = bytes(message)[i];\n }\n\n fullMessage[i+0] = byte(uint8(32));\n fullMessage[i+1] = byte(uint8(40));\n fullMessage[i+2] = byte(uint8(48 + ( errCode / 10 )));\n fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 )));\n fullMessage[i+4] = byte(uint8(41));\n\n require(errCode == uint(Error.NO_ERROR), string(fullMessage));\n }\n}\n" + }, + "contracts/Maximillion.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CEther.sol\";\n\n/**\n * @title Compound's Maximillion Contract\n * @author Compound\n */\ncontract Maximillion {\n /**\n * @notice The default cEther market to repay in\n */\n CEther public cEther;\n\n /**\n * @notice Construct a Maximillion to repay max in a CEther market\n */\n constructor(CEther cEther_) public {\n cEther = cEther_;\n }\n\n /**\n * @notice msg.sender sends Ether to repay an account's borrow in the cEther market\n * @dev The provided Ether is applied towards the borrow balance, any excess is refunded\n * @param borrower The address of the borrower account to repay on behalf of\n */\n function repayBehalf(address borrower) public payable {\n repayBehalfExplicit(borrower, cEther);\n }\n\n /**\n * @notice msg.sender sends Ether to repay an account's borrow in a cEther market\n * @dev The provided Ether is applied towards the borrow balance, any excess is refunded\n * @param borrower The address of the borrower account to repay on behalf of\n * @param cEther_ The address of the cEther contract to repay in\n */\n function repayBehalfExplicit(address borrower, CEther cEther_) public payable {\n uint received = msg.value;\n uint borrows = cEther_.borrowBalanceCurrent(borrower);\n if (received > borrows) {\n cEther_.repayBorrowBehalf.value(borrows)(borrower);\n msg.sender.transfer(received - borrows);\n } else {\n cEther_.repayBorrowBehalf.value(received)(borrower);\n }\n }\n}\n" + }, + "contracts/Reservoir.sol": { + "content": "pragma solidity ^0.5.16;\n\n/**\n * @title Reservoir Contract\n * @notice Distributes a token to a different contract at a fixed rate.\n * @dev This contract must be poked via the `drip()` function every so often.\n * @author Compound\n */\ncontract Reservoir {\n\n /// @notice The block number when the Reservoir started (immutable)\n uint public dripStart;\n\n /// @notice Tokens per block that to drip to target (immutable)\n uint public dripRate;\n\n /// @notice Reference to token to drip (immutable)\n EIP20Interface public token;\n\n /// @notice Target to receive dripped tokens (immutable)\n address public target;\n\n /// @notice Amount that has already been dripped\n uint public dripped;\n\n /**\n * @notice Constructs a Reservoir\n * @param dripRate_ Numer of tokens per block to drip\n * @param token_ The token to drip\n * @param target_ The recipient of dripped tokens\n */\n constructor(uint dripRate_, EIP20Interface token_, address target_) public {\n dripStart = block.number;\n dripRate = dripRate_;\n token = token_;\n target = target_;\n dripped = 0;\n }\n\n /**\n * @notice Drips the maximum amount of tokens to match the drip rate since inception\n * @dev Note: this will only drip up to the amount of tokens available.\n * @return The amount of tokens dripped in this call\n */\n function drip() public returns (uint) {\n // First, read storage into memory\n EIP20Interface token_ = token;\n uint reservoirBalance_ = token_.balanceOf(address(this)); // TODO: Verify this is a static call\n uint dripRate_ = dripRate;\n uint dripStart_ = dripStart;\n uint dripped_ = dripped;\n address target_ = target;\n uint blockNumber_ = block.number;\n\n // Next, calculate intermediate values\n uint dripTotal_ = mul(dripRate_, blockNumber_ - dripStart_, \"dripTotal overflow\");\n uint deltaDrip_ = sub(dripTotal_, dripped_, \"deltaDrip underflow\");\n uint toDrip_ = min(reservoirBalance_, deltaDrip_);\n uint drippedNext_ = add(dripped_, toDrip_, \"tautological\");\n\n // Finally, write new `dripped` value and transfer tokens to target\n dripped = drippedNext_;\n token_.transfer(target_, toDrip_);\n\n return toDrip_;\n }\n\n /* Internal helper functions for safe math */\n\n function add(uint a, uint b, string memory errorMessage) internal pure returns (uint) {\n uint c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {\n require(b <= a, errorMessage);\n uint c = a - b;\n return c;\n }\n\n function mul(uint a, uint b, string memory errorMessage) internal pure returns (uint) {\n if (a == 0) {\n return 0;\n }\n uint c = a * b;\n require(c / a == b, errorMessage);\n return c;\n }\n\n function min(uint a, uint b) internal pure returns (uint) {\n if (a <= b) {\n return a;\n } else {\n return b;\n }\n }\n}\n\nimport \"./EIP20Interface.sol\";\n" + }, + "contracts/CErc20Delegator.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CTokenInterfaces.sol\";\n\n/**\n * @title Compound's CErc20Delegator Contract\n * @notice CTokens which wrap an EIP-20 underlying and delegate to an implementation\n * @author Compound\n */\ncontract CErc20Delegator is CTokenInterface, CErc20Interface, CDelegatorInterface {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param implementation_ The address of the implementation the contract delegates to\n * @param becomeImplementationData The encoded args for becomeImplementation\n */\n constructor(address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address implementation_,\n bytes memory becomeImplementationData) public {\n // Creator of the contract is admin during initialization\n admin = msg.sender;\n\n // First delegate gets to initialize the delegator (i.e. storage contract)\n delegateTo(implementation_, abi.encodeWithSignature(\"initialize(address,address,address,uint256,string,string,uint8)\",\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_));\n\n // New implementations always get set via the settor (post-initialize)\n _setImplementation(implementation_, false, becomeImplementationData);\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n }\n\n /**\n * @notice Called by the admin to update the implementation of the delegator\n * @param implementation_ The address of the new implementation for delegation\n * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation\n * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation\n */\n function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public {\n require(msg.sender == admin, \"CErc20Delegator::_setImplementation: Caller must be admin\");\n\n if (allowResign) {\n delegateToImplementation(abi.encodeWithSignature(\"_resignImplementation()\"));\n }\n\n address oldImplementation = implementation;\n implementation = implementation_;\n\n delegateToImplementation(abi.encodeWithSignature(\"_becomeImplementation(bytes)\", becomeImplementationData));\n\n emit NewImplementation(oldImplementation, implementation);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives cTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function mint(uint mintAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"mint(uint256)\", mintAmount));\n return abi.decode(data, (uint));\n }\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 a failure (see ErrorReporter.sol for details)\n */\n function redeem(uint redeemTokens) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"redeem(uint256)\", redeemTokens));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to redeem\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function redeemUnderlying(uint redeemAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"redeemUnderlying(uint256)\", redeemAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function borrow(uint borrowAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"borrow(uint256)\", borrowAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function repayBorrow(uint repayAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"repayBorrow(uint256)\", repayAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"repayBorrowBehalf(address,uint256)\", borrower, repayAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this cToken to be liquidated\n * @param cTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"liquidateBorrow(address,uint256,address)\", borrower, repayAmount, cTokenCollateral));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transfer(address dst, uint amount) external returns (bool) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"transfer(address,uint256)\", dst, amount));\n return abi.decode(data, (bool));\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return Whether or not the transfer succeeded\n */\n function transferFrom(address src, address dst, uint256 amount) external returns (bool) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"transferFrom(address,address,uint256)\", src, dst, amount));\n return abi.decode(data, (bool));\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (-1 means infinite)\n * @return Whether or not the approval succeeded\n */\n function approve(address spender, uint256 amount) external returns (bool) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"approve(address,uint256)\", spender, amount));\n return abi.decode(data, (bool));\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return The number of tokens allowed to be spent (-1 means infinite)\n */\n function allowance(address owner, address spender) external view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"allowance(address,address)\", owner, spender));\n return abi.decode(data, (uint));\n }\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 (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"balanceOf(address)\", owner));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"balanceOfUnderlying(address)\", owner));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return (possible error, token balance, borrow balance, exchange rate mantissa)\n */\n function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"getAccountSnapshot(address)\", account));\n return abi.decode(data, (uint, uint, uint, uint));\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this cToken\n * @return The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"borrowRatePerBlock()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this cToken\n * @return The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"supplyRatePerBlock()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return The total borrows with interest\n */\n function totalBorrowsCurrent() external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"totalBorrowsCurrent()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return The calculated balance\n */\n function borrowBalanceCurrent(address account) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"borrowBalanceCurrent(address)\", account));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return The calculated balance\n */\n function borrowBalanceStored(address account) public view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"borrowBalanceStored(address)\", account));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"exchangeRateCurrent()\"));\n return abi.decode(data, (uint));\n }\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() public view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"exchangeRateStored()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Get cash balance of this cToken in the underlying asset\n * @return The quantity of underlying asset owned by this contract\n */\n function getCash() external view returns (uint) {\n bytes memory data = delegateToViewImplementation(abi.encodeWithSignature(\"getCash()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves.\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n */\n function accrueInterest() public returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"accrueInterest()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another cToken during the process of liquidation.\n * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of cTokens to seize\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"seize(address,address,uint256)\", liquidator, borrower, seizeTokens));\n return abi.decode(data, (uint));\n }\n\n /*** Admin Functions ***/\n\n /**\n * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n * @param newPendingAdmin New pending admin.\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_setPendingAdmin(address)\", newPendingAdmin));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Sets a new comptroller for the market\n * @dev Admin function to set a new comptroller\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_setComptroller(address)\", newComptroller));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_setReserveFactor(uint256)\", newReserveFactorMantissa));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\n * @dev Admin function for pending admin to accept role and update admin\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _acceptAdmin() external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_acceptAdmin()\"));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accrues interest and adds reserves by transferring from admin\n * @param addAmount Amount of reserves to add\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _addReserves(uint addAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_addReserves(uint256)\", addAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to admin\n * @param reduceAmount Amount of reduction to reserves\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _reduceReserves(uint reduceAmount) external returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_reduceReserves(uint256)\", reduceAmount));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)\n */\n function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {\n bytes memory data = delegateToImplementation(abi.encodeWithSignature(\"_setInterestRateModel(address)\", newInterestRateModel));\n return abi.decode(data, (uint));\n }\n\n /**\n * @notice Internal method to delegate execution to another contract\n * @dev It returns to the external caller whatever the implementation returns or forwards reverts\n * @param callee The contract to delegatecall\n * @param data The raw data to delegatecall\n * @return The returned bytes from the delegatecall\n */\n function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returnData) = callee.delegatecall(data);\n assembly {\n if eq(success, 0) {\n revert(add(returnData, 0x20), returndatasize)\n }\n }\n return returnData;\n }\n\n /**\n * @notice Delegates execution to the implementation contract\n * @dev It returns to the external caller whatever the implementation returns or forwards reverts\n * @param data The raw data to delegatecall\n * @return The returned bytes from the delegatecall\n */\n function delegateToImplementation(bytes memory data) public returns (bytes memory) {\n return delegateTo(implementation, data);\n }\n\n /**\n * @notice Delegates execution to an implementation contract\n * @dev It returns to the external caller whatever the implementation returns or forwards reverts\n * There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.\n * @param data The raw data to delegatecall\n * @return The returned bytes from the delegatecall\n */\n function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {\n (bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature(\"delegateToImplementation(bytes)\", data));\n assembly {\n if eq(success, 0) {\n revert(add(returnData, 0x20), returndatasize)\n }\n }\n return abi.decode(returnData, (bytes));\n }\n\n /**\n * @notice Delegates execution to an implementation contract\n * @dev It returns to the external caller whatever the implementation returns or forwards reverts\n */\n function () external payable {\n require(msg.value == 0,\"CErc20Delegator:fallback: cannot send value to fallback\");\n\n // delegate all other functions to current implementation\n (bool success, ) = implementation.delegatecall(msg.data);\n\n assembly {\n let free_mem_ptr := mload(0x40)\n returndatacopy(free_mem_ptr, 0, returndatasize)\n\n switch success\n case 0 { revert(free_mem_ptr, returndatasize) }\n default { return(free_mem_ptr, returndatasize) }\n }\n }\n}\n" + }, + "contracts/Stabilizer.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\nimport \"./ERC20.sol\";\n\ninterface IStrat {\n function invest() external; // underlying amount must be sent from vault to strat address before\n function divest(uint amount) external; // should send requested amount to vault directly, not less or more\n function calcTotalValue() external returns (uint);\n function underlying() external view returns (address);\n}\n\n// WARNING: This contract assumes synth and reserve are equally valuable and share the same decimals (e.g. Dola and Dai)\n// DO NOT USE WITH USDC OR USDT\n// DO NOT USE WITH NON-STANDARD ERC20 TOKENS\ncontract Stabilizer {\n using SafeMath for uint;\n\n uint public constant MAX_FEE = 1000; // 10%\n uint public constant FEE_DENOMINATOR = 10000;\n uint public buyFee;\n uint public sellFee;\n uint public supplyCap;\n uint public supply;\n ERC20 public synth;\n ERC20 public reserve;\n address public operator;\n IStrat public strat;\n address public governance;\n\n constructor(ERC20 synth_, ERC20 reserve_, address gov_, uint buyFee_, uint sellFee_, uint supplyCap_) public {\n require(buyFee_ <= MAX_FEE, \"buyFee_ too high\");\n require(sellFee_ <= MAX_FEE, \"sellFee_ too high\");\n synth = synth_;\n reserve = reserve_;\n governance = gov_;\n buyFee = buyFee_;\n sellFee = sellFee_;\n operator = msg.sender;\n supplyCap = supplyCap_;\n }\n\n modifier onlyOperator {\n require(msg.sender == operator || msg.sender == governance, \"ONLY OPERATOR OR GOV\");\n _;\n }\n\n modifier onlyGovernance {\n require(msg.sender == governance, \"ONLY GOV\");\n _;\n }\n\n function setOperator(address operator_) public {\n require(msg.sender == governance || msg.sender == operator, \"ONLY GOV OR OPERATOR\");\n require(operator_ != address(0), \"NO ADDRESS ZERO\");\n operator = operator_;\n }\n\n function setBuyFee(uint amount) public onlyGovernance {\n require(amount <= MAX_FEE, \"amount too high\");\n buyFee = amount;\n }\n\n function setSellFee(uint amount) public onlyGovernance {\n require(amount <= MAX_FEE, \"amount too high\");\n sellFee = amount;\n }\n \n function setCap(uint amount) public onlyOperator {\n supplyCap = amount;\n }\n\n function setGovernance(address gov_) public onlyGovernance {\n require(gov_ != address(0), \"NO ADDRESS ZERO\");\n governance = gov_;\n }\n\n function setStrat(IStrat newStrat) public onlyGovernance {\n require(newStrat.underlying() == address(reserve), \"Invalid strat\");\n if(address(strat) != address(0)) {\n uint prevTotalValue = strat.calcTotalValue();\n strat.divest(prevTotalValue);\n }\n reserve.transfer(address(newStrat), reserve.balanceOf(address(this)));\n newStrat.invest();\n strat = newStrat;\n }\n\n function removeStrat() public onlyGovernance {\n uint prevTotalValue = strat.calcTotalValue();\n strat.divest(prevTotalValue);\n\n strat = IStrat(address(0));\n }\n\n function takeProfit() public {\n uint totalReserves = getTotalReserves();\n if(totalReserves > supply) {\n uint profit = totalReserves - supply; // underflow prevented by if condition\n if(address(strat) != address(0)) {\n uint bal = reserve.balanceOf(address(this));\n if(bal < profit) {\n strat.divest(profit - bal); // underflow prevented by if condition\n }\n }\n reserve.transfer(governance, profit);\n }\n }\n\n function buy(uint amount) public {\n require(supply.add(amount) <= supplyCap, \"supply exceeded cap\");\n if(address(strat) != address(0)) {\n reserve.transferFrom(msg.sender, address(strat), amount);\n strat.invest();\n } else {\n reserve.transferFrom(msg.sender, address(this), amount);\n }\n\n if(buyFee > 0) {\n uint fee = amount.mul(buyFee).div(FEE_DENOMINATOR);\n reserve.transferFrom(msg.sender, governance, fee);\n emit Buy(msg.sender, amount, amount.add(fee));\n } else {\n emit Buy(msg.sender, amount, amount);\n }\n\n synth.mint(msg.sender, amount);\n supply = supply.add(amount);\n }\n\n function sell(uint amount) public {\n synth.transferFrom(msg.sender, address(this), amount);\n synth.burn(amount);\n\n uint reserveBal = reserve.balanceOf(address(this));\n if(address(strat) != address(0) && reserveBal < amount) {\n strat.divest(amount - reserveBal); // underflow prevented by if condition\n }\n\n uint afterFee;\n if(sellFee > 0) {\n uint fee = amount.mul(sellFee).div(FEE_DENOMINATOR);\n afterFee = amount.sub(fee);\n reserve.transfer(governance, fee);\n } else {\n afterFee = amount;\n }\n \n reserve.transfer(msg.sender, afterFee);\n supply = supply.sub(amount);\n emit Sell(msg.sender, amount, afterFee);\n }\n\n function rescue(ERC20 token) public onlyGovernance {\n require(token != reserve, \"RESERVE CANNOT BE RESCUED\");\n token.transfer(governance, token.balanceOf(address(this)));\n }\n\n function getTotalReserves() internal returns (uint256 bal) { // new view function because strat.calcTotalValue() is not view function\n bal = reserve.balanceOf(address(this));\n if(address(strat) != address(0)) {\n bal = bal.add(strat.calcTotalValue());\n }\n }\n\n event Buy(address indexed user, uint purchased, uint spent);\n event Sell(address indexed user, uint sold, uint received);\n}" + }, + "contracts/CYFI.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CErc20.sol\";\n\ninterface IDelegateRegistry {\n function setDelegate(bytes32 id, address delegate) external;\n}\n\ncontract CYFI is CErc20 {\n\n IDelegateRegistry public delegateRegistry;\n\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n */\n constructor(address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n IDelegateRegistry delegateRegistry_) public {\n // Creator of the contract is admin during initialization\n admin = msg.sender;\n\n // Initialize the market\n initialize(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n\n // set delegate registry\n delegateRegistry = delegateRegistry_;\n }\n\n function delegate(address delegate_) public {\n require(msg.sender == admin, \"only admin may delegate\");\n // ybaby.eth is the id used for YFI governance\n delegateRegistry.setDelegate('ybaby.eth', delegate_);\n }\n\n}\n" + }, + "contracts/CErc20Immutable.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title Compound's CErc20Immutable Contract\n * @notice CTokens which wrap an EIP-20 underlying and are immutable\n * @author Compound\n */\ncontract CErc20Immutable is CErc20 {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n */\n constructor(address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_) public {\n // Creator of the contract is admin during initialization\n admin = msg.sender;\n\n // Initialize the market\n initialize(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);\n\n // Set the proper admin now that initialization is done\n admin = admin_;\n }\n}\n" + }, + "contracts/CErc20Delegate.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title Compound's CErc20Delegate Contract\n * @notice CTokens which wrap an EIP-20 underlying and are delegated to\n * @author Compound\n */\ncontract CErc20Delegate is CErc20, CDelegateInterface {\n /**\n * @notice Construct an empty delegate\n */\n constructor() public {}\n\n /**\n * @notice Called by the delegator on a delegate to initialize it for duty\n * @param data The encoded bytes data for any initialization\n */\n function _becomeImplementation(bytes memory data) public {\n // Shh -- currently unused\n data;\n\n // Shh -- we don't ever want this hook to be marked pure\n if (false) {\n implementation = address(0);\n }\n\n require(msg.sender == admin, \"only the admin may call _becomeImplementation\");\n }\n\n /**\n * @notice Called by the delegator on a delegate to forfeit its responsibility\n */\n function _resignImplementation() public {\n // Shh -- we don't ever want this hook to be marked pure\n if (false) {\n implementation = address(0);\n }\n\n require(msg.sender == admin, \"only the admin may call _resignImplementation\");\n }\n}\n" + }, + "contracts/CDaiDelegate.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CErc20Delegate.sol\";\n\n/**\n * @title Compound's CDai Contract\n * @notice CToken which wraps Multi-Collateral DAI\n * @author Compound\n */\ncontract CDaiDelegate is CErc20Delegate {\n /**\n * @notice DAI adapter address\n */\n address public daiJoinAddress;\n\n /**\n * @notice DAI Savings Rate (DSR) pot address\n */\n address public potAddress;\n\n /**\n * @notice DAI vat address\n */\n address public vatAddress;\n\n /**\n * @notice Delegate interface to become the implementation\n * @param data The encoded arguments for becoming\n */\n function _becomeImplementation(bytes memory data) public {\n require(msg.sender == admin, \"only the admin may initialize the implementation\");\n\n (address daiJoinAddress_, address potAddress_) = abi.decode(data, (address, address));\n return _becomeImplementation(daiJoinAddress_, potAddress_);\n }\n\n /**\n * @notice Explicit interface to become the implementation\n * @param daiJoinAddress_ DAI adapter address\n * @param potAddress_ DAI Savings Rate (DSR) pot address\n */\n function _becomeImplementation(address daiJoinAddress_, address potAddress_) internal {\n // Get dai and vat and sanity check the underlying\n DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress_);\n PotLike pot = PotLike(potAddress_);\n GemLike dai = daiJoin.dai();\n VatLike vat = daiJoin.vat();\n require(address(dai) == underlying, \"DAI must be the same as underlying\");\n\n // Remember the relevant addresses\n daiJoinAddress = daiJoinAddress_;\n potAddress = potAddress_;\n vatAddress = address(vat);\n\n // Approve moving our DAI into the vat through daiJoin\n dai.approve(daiJoinAddress, uint(-1));\n\n // Approve the pot to transfer our funds within the vat\n vat.hope(potAddress);\n vat.hope(daiJoinAddress);\n\n // Accumulate DSR interest -- must do this in order to doTransferIn\n pot.drip();\n\n // Transfer all cash in (doTransferIn does this regardless of amount)\n doTransferIn(address(this), 0);\n }\n\n /**\n * @notice Delegate interface to resign the implementation\n */\n function _resignImplementation() public {\n require(msg.sender == admin, \"only the admin may abandon the implementation\");\n\n // Transfer all cash out of the DSR - note that this relies on self-transfer\n DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);\n PotLike pot = PotLike(potAddress);\n VatLike vat = VatLike(vatAddress);\n\n // Accumulate interest\n pot.drip();\n\n // Calculate the total amount in the pot, and move it out\n uint pie = pot.pie(address(this));\n pot.exit(pie);\n\n // Checks the actual balance of DAI in the vat after the pot exit\n uint bal = vat.dai(address(this));\n\n // Remove our whole balance\n daiJoin.exit(address(this), bal / RAY);\n }\n\n /*** CToken Overrides ***/\n\n /**\n * @notice Accrues DSR then applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n */\n function accrueInterest() public returns (uint) {\n // Accumulate DSR interest\n PotLike(potAddress).drip();\n\n // Accumulate CToken interest\n return super.accrueInterest();\n }\n\n /*** Safe Token ***/\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function getCashPrior() internal view returns (uint) {\n PotLike pot = PotLike(potAddress);\n uint pie = pot.pie(address(this));\n return mul(pot.chi(), pie) / RAY;\n }\n\n /**\n * @notice Transfer the underlying to this contract and sweep into DSR pot\n * @param from Address to transfer funds from\n * @param amount Amount of underlying to transfer\n * @return The actual amount that is transferred\n */\n function doTransferIn(address from, uint amount) internal returns (uint) {\n // Perform the EIP-20 transfer in\n EIP20Interface token = EIP20Interface(underlying);\n require(token.transferFrom(from, address(this), amount), \"unexpected EIP-20 transfer in return\");\n\n DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);\n GemLike dai = GemLike(underlying);\n PotLike pot = PotLike(potAddress);\n VatLike vat = VatLike(vatAddress);\n\n // Convert all our DAI to internal DAI in the vat\n daiJoin.join(address(this), dai.balanceOf(address(this)));\n\n // Checks the actual balance of DAI in the vat after the join\n uint bal = vat.dai(address(this));\n\n // Calculate the percentage increase to th pot for the entire vat, and move it in\n // Note: We may leave a tiny bit of DAI in the vat...but we do the whole thing every time\n uint pie = bal / pot.chi();\n pot.join(pie);\n\n return amount;\n }\n\n /**\n * @notice Transfer the underlying from this contract, after sweeping out of DSR pot\n * @param to Address to transfer funds to\n * @param amount Amount of underlying to transfer\n */\n function doTransferOut(address payable to, uint amount) internal {\n DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);\n PotLike pot = PotLike(potAddress);\n\n // Calculate the percentage decrease from the pot, and move that much out\n // Note: Use a slightly larger pie size to ensure that we get at least amount in the vat\n uint pie = add(mul(amount, RAY) / pot.chi(), 1);\n pot.exit(pie);\n\n daiJoin.exit(to, amount);\n }\n\n /*** Maker Internals ***/\n\n uint256 constant RAY = 10 ** 27;\n\n function add(uint x, uint y) internal pure returns (uint z) {\n require((z = x + y) >= x, \"add-overflow\");\n }\n\n function mul(uint x, uint y) internal pure returns (uint z) {\n require(y == 0 || (z = x * y) / y == x, \"mul-overflow\");\n }\n}\n\n/*** Maker Interfaces ***/\n\ninterface PotLike {\n function chi() external view returns (uint);\n function pie(address) external view returns (uint);\n function drip() external returns (uint);\n function join(uint) external;\n function exit(uint) external;\n}\n\ninterface GemLike {\n function approve(address, uint) external;\n function balanceOf(address) external view returns (uint);\n function transferFrom(address, address, uint) external returns (bool);\n}\n\ninterface VatLike {\n function dai(address) external view returns (uint);\n function hope(address) external;\n}\n\ninterface DaiJoinLike {\n function vat() external returns (VatLike);\n function dai() external returns (GemLike);\n function join(address, uint) external payable;\n function exit(address, uint) external;\n}\n" + }, + "contracts/CCompLikeDelegate.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./CErc20Delegate.sol\";\n\ninterface CompLike {\n function delegate(address delegatee) external;\n}\n\n/**\n * @title Compound's CCompLikeDelegate Contract\n * @notice CTokens which can 'delegate votes' of their underlying ERC-20\n * @author Compound\n */\ncontract CCompLikeDelegate is CErc20Delegate {\n /**\n * @notice Construct an empty delegate\n */\n constructor() public CErc20Delegate() {}\n\n /**\n * @notice Admin call to delegate the votes of the COMP-like underlying\n * @param compLikeDelegatee The address to delegate votes to\n */\n function _delegateCompLikeTo(address compLikeDelegatee) external {\n require(msg.sender == admin, \"only the admin may set the comp-like delegate\");\n CompLike(underlying).delegate(compLikeDelegatee);\n }\n}\n" + }, + "contracts/Oracle.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./PriceOracle.sol\";\n\ninterface Feed {\n function decimals() external view returns (uint8);\n function latestAnswer() external view returns (uint);\n}\n\ncontract Oracle is PriceOracle {\n\n struct FeedData {\n address addr;\n uint8 tokenDecimals;\n }\n\n address public owner;\n mapping (address => FeedData) public feeds; // cToken -> feed data\n mapping (address => uint) public fixedPrices; // cToken -> price\n uint8 constant DECIMALS = 36;\n\n modifier onlyOwner {\n require(msg.sender == owner, \"ONLY OWNER\");\n _;\n }\n\n constructor() public {\n owner = msg.sender;\n }\n\n function changeOwner(address owner_) public onlyOwner {\n owner = owner_;\n }\n\n function setFeed(CToken cToken_, address feed_, uint8 tokenDecimals_) public onlyOwner {\n feeds[address(cToken_)] = FeedData(feed_, tokenDecimals_);\n }\n\n function removeFeed(CToken cToken_) public onlyOwner {\n delete feeds[address(cToken_)];\n }\n\n function setFixedPrice(CToken cToken_, uint price) public onlyOwner {\n fixedPrices[address(cToken_)] = price;\n }\n\n function removeFixedPrice(CToken cToken_) public onlyOwner {\n delete fixedPrices[address(cToken_)];\n }\n\n function getUnderlyingPrice(CToken cToken_) public view returns (uint) {\n FeedData memory feed = feeds[address(cToken_)]; // gas savings\n if(feed.addr != address(0)) {\n uint decimals = uint(DECIMALS - feed.tokenDecimals - Feed(feed.addr).decimals());\n require(decimals <= DECIMALS, \"DECIMAL UNDERFLOW\");\n return Feed(feed.addr).latestAnswer() * (10 ** decimals);\n }\n\n return fixedPrices[address(cToken_)];\n }\n\n}" + }, + "contracts/StethFeed.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\n\ninterface IFeed {\n function decimals() external view returns (uint8);\n function latestAnswer() external view returns (uint);\n}\n\ninterface StethEthFeed {\n function current_price() external view returns (uint256 price, bool is_safe);\n}\n\ncontract StethFeed is IFeed {\n using SafeMath for uint;\n\n StethEthFeed public stethEthFeed;\n IFeed public ethFeed;\n\n constructor(StethEthFeed _stethEthFeed, IFeed _ethFeed) public {\n stethEthFeed = _stethEthFeed;\n ethFeed = _ethFeed;\n }\n\n function decimals() public view returns(uint8) {\n return 18;\n }\n\n function latestAnswer() public view returns (uint) {\n (uint stethEthPrice, bool isSafe) = stethEthFeed.current_price();\n require(isSafe, \"price is not safe\");\n return stethEthPrice\n .mul(ethFeed.latestAnswer())\n .div(10**uint256(ethFeed.decimals()));\n }\n\n}" + }, + "contracts/JumpRateModel.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./InterestRateModel.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title Compound's JumpRateModel Contract\n * @author Compound\n */\ncontract JumpRateModel is InterestRateModel {\n using SafeMath for uint;\n\n event NewInterestParams(uint baseRatePerBlock, uint multiplierPerBlock, uint jumpMultiplierPerBlock, uint kink);\n\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint public constant blocksPerYear = 2102400;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint public baseRatePerBlock;\n\n /**\n * @notice The multiplierPerBlock after hitting a specified utilization point\n */\n uint public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint public kink;\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by 1e18)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) public {\n baseRatePerBlock = baseRatePerYear.div(blocksPerYear);\n multiplierPerBlock = multiplierPerYear.div(blocksPerYear);\n jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear);\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @return The utilization rate as a mantissa between [0, 1e18]\n */\n function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) {\n // Utilization rate is 0 when there are no borrows\n if (borrows == 0) {\n return 0;\n }\n\n return borrows.mul(1e18).div(cash.add(borrows).sub(reserves));\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(uint cash, uint borrows, uint reserves) public view returns (uint) {\n uint util = utilizationRate(cash, borrows, reserves);\n\n if (util <= kink) {\n return util.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n } else {\n uint normalRate = kink.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock);\n uint excessUtil = util.sub(kink);\n return excessUtil.mul(jumpMultiplierPerBlock).div(1e18).add(normalRate);\n }\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @return The supply rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) {\n uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa);\n uint borrowRate = getBorrowRate(cash, borrows, reserves);\n uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18);\n return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18);\n }\n}\n" + }, + "contracts/InvFeed.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./SafeMath.sol\";\n\ninterface IFeed {\n function decimals() external view returns (uint8);\n function latestAnswer() external view returns (uint);\n}\n\ninterface IKeep3rV2 {\n function current(address tokenIn, uint amountIn, address tokenOut) external view returns (uint256 amountOut, uint lastUpdatedAgo);\n}\n\ncontract InvFeed is IFeed {\n using SafeMath for uint;\n\n IKeep3rV2 public keep3rV2Feed;\n IFeed public ethFeed;\n address public inv;\n address public weth;\n\n constructor(IKeep3rV2 _keep3rV2Feed, IFeed _ethFeed, address _inv, address _weth) public {\n keep3rV2Feed = _keep3rV2Feed;\n ethFeed = _ethFeed;\n inv = _inv;\n weth = _weth;\n }\n\n function decimals() public view returns(uint8) {\n return 18;\n }\n\n function latestAnswer() public view returns (uint) {\n (uint invEthPrice, ) = keep3rV2Feed.current(inv, 1e18, weth);\n return invEthPrice\n .mul(ethFeed.latestAnswer())\n .div(10**uint256(ethFeed.decimals()));\n }\n\n}" + }, + "contracts/DAIInterestRateModelV3.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"./JumpRateModelV2.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @title Compound's DAIInterestRateModel Contract (version 3)\n * @author Compound (modified by Dharma Labs)\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper.\n * Version 3 modifies the interest rate model in Version 2 by increasing the initial \"gap\" or slope of\n * the model prior to the \"kink\" from 2% to 4%, and enabling updateable parameters.\n */\ncontract DAIInterestRateModelV3 is JumpRateModelV2 {\n using SafeMath for uint;\n\n /**\n * @notice The additional margin per block separating the base borrow rate from the roof.\n */\n uint public gapPerBlock;\n\n /**\n * @notice The assumed (1 - reserve factor) used to calculate the minimum borrow rate (reserve factor = 0.05)\n */\n uint public constant assumedOneMinusReserveFactorMantissa = 0.95e18;\n\n PotLike pot;\n JugLike jug;\n\n /**\n * @notice Construct an interest rate model\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param pot_ The address of the Dai pot (where DSR is earned)\n * @param jug_ The address of the Dai jug (where SF is kept)\n * @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly)\n */\n constructor(uint jumpMultiplierPerYear, uint kink_, address pot_, address jug_, address owner_) JumpRateModelV2(0, 0, jumpMultiplierPerYear, kink_, owner_) public {\n gapPerBlock = 4e16 / blocksPerYear;\n pot = PotLike(pot_);\n jug = JugLike(jug_);\n poke();\n }\n\n /**\n * @notice External function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by 1e18). For DAI, this is calculated from DSR and SF. Input not used.\n * @param gapPerYear The Additional margin per year separating the base borrow rate from the roof. (scaled by 1e18)\n * @param jumpMultiplierPerYear The jumpMultiplierPerYear after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function updateJumpRateModel(uint baseRatePerYear, uint gapPerYear, uint jumpMultiplierPerYear, uint kink_) external {\n require(msg.sender == owner, \"only the owner may call this function.\");\n gapPerBlock = gapPerYear / blocksPerYear;\n updateJumpRateModelInternal(0, 0, jumpMultiplierPerYear, kink_);\n poke();\n }\n\n /**\n * @notice Calculates the current supply interest rate per block including the Dai savings rate\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amnount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) {\n uint protocolRate = super.getSupplyRate(cash, borrows, reserves, reserveFactorMantissa);\n\n uint underlying = cash.add(borrows).sub(reserves);\n if (underlying == 0) {\n return protocolRate;\n } else {\n uint cashRate = cash.mul(dsrPerBlock()).div(underlying);\n return cashRate.add(protocolRate);\n }\n }\n\n /**\n * @notice Calculates the Dai savings rate per block\n * @return The Dai savings rate per block (as a percentage, and scaled by 1e18)\n */\n function dsrPerBlock() public view returns (uint) {\n return pot\n .dsr().sub(1e27) // scaled 1e27 aka RAY, and includes an extra \"ONE\" before subraction\n .div(1e9) // descale to 1e18\n .mul(15); // 15 seconds per block\n }\n\n /**\n * @notice Resets the baseRate and multiplier per block based on the stability fee and Dai savings rate\n */\n function poke() public {\n (uint duty, ) = jug.ilks(\"ETH-A\");\n uint stabilityFeePerBlock = duty.add(jug.base()).sub(1e27).mul(1e18).div(1e27).mul(15);\n\n // We ensure the minimum borrow rate >= DSR / (1 - reserve factor)\n baseRatePerBlock = dsrPerBlock().mul(1e18).div(assumedOneMinusReserveFactorMantissa);\n\n // The roof borrow rate is max(base rate, stability fee) + gap, from which we derive the slope\n if (baseRatePerBlock < stabilityFeePerBlock) {\n multiplierPerBlock = stabilityFeePerBlock.sub(baseRatePerBlock).add(gapPerBlock).mul(1e18).div(kink);\n } else {\n multiplierPerBlock = gapPerBlock.mul(1e18).div(kink);\n }\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n}\n\n\n/*** Maker Interfaces ***/\n\ncontract PotLike {\n function chi() external view returns (uint);\n function dsr() external view returns (uint);\n function rho() external view returns (uint);\n function pie(address) external view returns (uint);\n function drip() external returns (uint);\n function join(uint) external;\n function exit(uint) external;\n}\n\ncontract JugLike {\n // --- Data ---\n struct Ilk {\n uint256 duty;\n uint256 rho;\n }\n\n mapping (bytes32 => Ilk) public ilks;\n uint256 public base;\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/hardhat.config.js b/hardhat.config.js index 4fbca2290..b49777883 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -2,7 +2,6 @@ require("@nomiclabs/hardhat-waffle"); require('@nomiclabs/hardhat-etherscan') require('hardhat-deploy') require('dotenv').config() -require('@eth-optimism/smock/build/src/plugins/hardhat-storagelayout') // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more diff --git a/package.json b/package.json index ed58646d6..e68702cf0 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ }, "dependencies": { "@0xsequence/multicall": "^0.10.8", - "@eth-optimism/smock": "^0.2.1-alpha.0", "@nomiclabs/hardhat-etherscan": "^2.1.0", "cli-table": "^0.3.5", "dotenv": "^8.2.0", diff --git a/test/Oracle.js b/test/Oracle.js deleted file mode 100644 index 8e12a9fab..000000000 --- a/test/Oracle.js +++ /dev/null @@ -1,120 +0,0 @@ -const { expect } = require("chai"); -const { smockit } = require('@eth-optimism/smock') - -const FeedInterface = new ethers.utils.Interface([ - 'function decimals() external view returns (uint8)', - 'function latestAnswer() external view returns (uint)' -]) - -describe("Oracle", function() { - - let oracle; - - it("Should set owner at deployment", async function() { - const Oracle = await ethers.getContractFactory("Oracle"); - oracle = await Oracle.deploy(); - - await oracle.deployed(); - expect(await oracle.owner()).to.equal((await ethers.getSigners())[0].address); - }); - - it("Should allow owner to set price feed", async function() { - const CTOKEN = "0x0000000000000000000000000000000000000001" - const feed = await smockit(FeedInterface) - await oracle.setFeed(CTOKEN, feed.address, 8); - expect((await oracle.feeds(CTOKEN))[0]).to.equal(feed.address); - expect((await oracle.feeds(CTOKEN))[1]).to.equal(8); - }) - - it("Should not allow non-owners to set price feed", async function() { - const CTOKEN = "0x0000000000000000000000000000000000000002" - const feed = await smockit(FeedInterface) - const [deployer, user] = await ethers.getSigners() - oracle = oracle.connect(user) - await expect(oracle.setFeed(CTOKEN, feed.address, 8)).to.be.revertedWith("ONLY OWNER"); - oracle = oracle.connect(deployer) - }) - - it("Should retrieve price from feed", async function() { - const CTOKEN = "0x0000000000000000000000000000000000000003" - const feed = await smockit(FeedInterface) - await oracle.setFeed(CTOKEN, feed.address, 18); - const input = "135808146155" - const output = "1358081461550000000000" - feed.smocked.decimals.will.return.with(8) - feed.smocked.latestAnswer.will.return.with(input) - expect(await oracle.getUnderlyingPrice(CTOKEN)).to.equal(output) - await oracle.setFeed(CTOKEN, feed.address, 8); - const input2 = "3537245298663" - const output2 = "353724529866300000000000000000000" - feed.smocked.decimals.will.return.with(8) - feed.smocked.latestAnswer.will.return.with(input2) - expect(await oracle.getUnderlyingPrice(CTOKEN)).to.equal(output2) - }) - - it("Should return 0 for unavailable prices", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000004" - expect(await oracle.getUnderlyingPrice(CTOKEN)).to.equal(0) - }) - - it("Should allow owner to remove price feed", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000001" - await oracle.removeFeed(CTOKEN); - expect((await oracle.feeds(CTOKEN))[0]).to.equal(ethers.constants.AddressZero); - expect((await oracle.feeds(CTOKEN))[1]).to.equal(0); - }) - - it("Should not allow non-owners to remove price feed", async function() { - const CTOKEN = "0x0000000000000000000000000000000000000003" - const [deployer, user] = await ethers.getSigners() - oracle = oracle.connect(user) - await expect(oracle.removeFeed(CTOKEN)).to.be.revertedWith("ONLY OWNER"); - oracle = oracle.connect(deployer) - }) - - it("Should allow owner to set fixed price", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000005" - const price = "1000000000000000000" - await oracle.setFixedPrice(CTOKEN, price); - expect(await oracle.fixedPrices(CTOKEN)).to.equal(price) - expect(await oracle.getUnderlyingPrice(CTOKEN)).to.equal(price) - }) - - it("Should not allow non-owner to set fixed price", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000005" - const price = "1000000000000000000" - const [deployer, user] = await ethers.getSigners() - oracle = oracle.connect(user) - await expect(oracle.setFixedPrice(CTOKEN, price)).to.be.revertedWith("ONLY OWNER"); - oracle = oracle.connect(deployer) - }) - - it("Should allow owner to remove fixed price", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000005" - await oracle.removeFixedPrice(CTOKEN); - expect(await oracle.fixedPrices(CTOKEN)).to.equal(0) - expect(await oracle.getUnderlyingPrice(CTOKEN)).to.equal(0) - }) - - it("Should not allow non-owner to remove fixed price", async function () { - const CTOKEN = "0x0000000000000000000000000000000000000005" - const [deployer, user] = await ethers.getSigners() - oracle = oracle.connect(user) - await expect(oracle.removeFixedPrice(CTOKEN)).to.be.revertedWith("ONLY OWNER"); - oracle = oracle.connect(deployer) - }) - - it("Should not allow non-owner to change owner", async function() { - const [deployer, user] = await ethers.getSigners() - oracle = oracle.connect(user) - await expect(oracle.changeOwner(ethers.constants.AddressZero)).to.be.revertedWith("ONLY OWNER"); - oracle = oracle.connect(deployer) - }) - - it("Should allow owner to change owner", async function() { - await oracle.changeOwner(ethers.constants.AddressZero); - expect(await oracle.owner()).to.equal(ethers.constants.AddressZero) - }) - - -}); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 38ede0a0e..a1678b68d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -513,18 +513,6 @@ resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA== -"@eth-optimism/smock@^0.2.1-alpha.0": - version "0.2.1-alpha.0" - resolved "https://registry.yarnpkg.com/@eth-optimism/smock/-/smock-0.2.1-alpha.0.tgz#83ee0cd5484a7a0f76e836304f2a5b75a5a95eb9" - integrity sha512-8jrGaQOW2iRHi0XBDWr2OfIgJZEiCSyMaWw8MC3wjXjFAW1nPI66zKfUzBDC6XR3VZ0REJiAzxv/RO2GwRuuZg== - dependencies: - "@nomiclabs/hardhat-ethers" "^2.0.0" - "@nomiclabs/hardhat-waffle" "^2.0.0" - ethereum-waffle "^3" - ethers "^5" - fs-extra "^9.0.1" - hardhat "^2.0.3" - "@ethereum-waffle/chai@^3.2.1": version "3.2.1" resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.2.1.tgz#5cb542b2a323adf0bc2dda00f48b0eb85944d8ab" @@ -1698,27 +1686,6 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@nomiclabs/ethereumjs-vm@^4.1.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@nomiclabs/ethereumjs-vm/-/ethereumjs-vm-4.2.1.tgz#768a6a071f88a9f3d27e560b899f86191d53bb72" - integrity sha512-vVloT6g/QNPasIrGWpR583b9nn1cBjNIQtaVdunEvwVFnEmTpsE0U67OiAiqYZmd0g7zqQrj2jepw0GEgnAz7Q== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - core-js-pure "^3.0.1" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.2" - ethereumjs-blockchain "^4.0.3" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.2" - ethereumjs-util "^6.2.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - util.promisify "^1.0.0" - "@nomiclabs/hardhat-ethers@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.1.tgz#f86a6fa210dbe6270adffccc75e93ed60a856904" @@ -5354,7 +5321,7 @@ ethereum-types@^3.2.0: "@types/node" "*" bignumber.js "~9.0.0" -ethereum-waffle@^3, ethereum-waffle@^3.0.0: +ethereum-waffle@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-3.2.1.tgz#9d6d6b93484c5e1b77dfdeb646c050ed877e836e" integrity sha512-Fhg7BaBuV+Xo5XT+NEC3UTKGunvpq+iQPglZbIAJF6ZcwQwkiKfJUDuB0ZSkg5ntbRS4gpahfoXj1nTzdtx8UA== @@ -5406,7 +5373,7 @@ ethereumjs-account@^2.0.3: rlp "^2.0.0" safe-buffer "^5.1.1" -ethereumjs-block@2.2.2, ethereumjs-block@^2.2.0, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: +ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== @@ -5502,32 +5469,6 @@ ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0: rlp "^2.0.0" secp256k1 "^3.0.1" -ethereumjs-util@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-util@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.7, ethereumjs-util@^7.0.8, ethereumjs-util@^7.0.9: version "7.0.10" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f" @@ -5622,7 +5563,7 @@ ethers@4.0.0-beta.3: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5, ethers@^5.0.0, ethers@^5.0.1: +ethers@^5.0.0, ethers@^5.0.1: version "5.0.26" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.26.tgz#ef43c6b6aad71f10c1a184003f69b142d7d03bae" integrity sha512-MqA8Fvutn3qEW0yBJOHeV6KZmRpF2rqlL2B5058AGkUFsuu6j5Ns/FRlMsbGeQwBz801IB23jQp7vjRfFsKSkg== @@ -6295,7 +6236,7 @@ fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0, fs-extra@^9.0.1: +fs-extra@^9.0.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -6802,56 +6743,6 @@ hardhat-deploy@^0.7.0-beta.44: murmur-128 "^0.2.1" qs "^6.9.4" -hardhat@^2.0.3: - version "2.0.8" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.0.8.tgz#6ec232293dd6b3ca7baeadb095ba4afce4b9b2e0" - integrity sha512-2tDAtOfshrBzP103dx7PQrhTwv2sqjhQStZAPwkkQTic25o2EH6HYE2++LuOG98YwqSjr0WvhvdBvKl3dCSkYA== - dependencies: - "@nomiclabs/ethereumjs-vm" "^4.1.1" - "@sentry/node" "^5.18.1" - "@solidity-parser/parser" "^0.11.0" - "@types/bn.js" "^4.11.5" - "@types/lru-cache" "^5.1.0" - abort-controller "^3.0.0" - adm-zip "^0.4.16" - ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - eth-sig-util "^2.5.2" - ethereum-cryptography "^0.1.2" - ethereumjs-abi "^0.6.8" - ethereumjs-account "^3.0.0" - ethereumjs-block "^2.2.0" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^6.1.0" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "^7.1.3" - immutable "^4.0.0-rc.12" - io-ts "1.10.4" - lodash "^4.17.11" - merkle-patricia-tree "^3.0.0" - mocha "^7.1.2" - node-fetch "^2.6.0" - qs "^6.7.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - slash "^3.0.0" - solc "0.7.3" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - "true-case-path" "^2.2.1" - tsort "0.0.1" - uuid "^3.3.2" - ws "^7.2.1" - hardhat@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.2.1.tgz#bef0031b994e3f60a88d428f2097195c58cf9ed2" @@ -8646,15 +8537,6 @@ level-ws@0.0.0: readable-stream "~1.0.15" xtend "~2.1.1" -level-ws@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-1.0.0.tgz#19a22d2d4ac57b18cc7c6ecc4bd23d899d8f603b" - integrity sha512-RXEfCmkd6WWFlArh3X8ONvQPm8jNpfA0s/36M4QzLqrLEIt1iJE9WBHLZ5vZJK6haMjJPJGJCQWfjMNnRcq/9Q== - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.8" - xtend "^4.0.1" - level-ws@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" @@ -9035,19 +8917,6 @@ merkle-patricia-tree@2.3.2, merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2 rlp "^2.0.0" semaphore ">=1.0.1" -merkle-patricia-tree@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-3.0.0.tgz#448d85415565df72febc33ca362b8b614f5a58f8" - integrity sha512-soRaMuNf/ILmw3KWbybaCjhx86EYeBbD8ph0edQCTed0JN/rxDt1EBN52Ajre3VyGo+91f8+/rfPIRQnnGMqmQ== - dependencies: - async "^2.6.1" - ethereumjs-util "^5.2.0" - level-mem "^3.0.1" - level-ws "^1.0.0" - readable-stream "^3.0.6" - rlp "^2.0.0" - semaphore ">=1.0.1" - merkle-patricia-tree@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.1.0.tgz#010636c4cfd68682df33a2e3186b7d0be7b98b9d" @@ -10558,7 +10427,7 @@ readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10571,7 +10440,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.1, readable-stream@^3.0.6, readable-stream@^3.1.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.1, readable-stream@^3.1.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==