From a5643813cc2df4360709f9dd7bd60beea9f69499 Mon Sep 17 00:00:00 2001 From: n3bs Date: Tue, 22 Mar 2022 22:09:07 -0500 Subject: [PATCH 1/3] Add FtmFeed --- contracts/FtmFeed.sol | 33 +++++++++++++++++++++++++++++++++ deploy/35_ftmFeed.js | 15 +++++++++++++++ 2 files changed, 48 insertions(+) create mode 100755 contracts/FtmFeed.sol create mode 100644 deploy/35_ftmFeed.js diff --git a/contracts/FtmFeed.sol b/contracts/FtmFeed.sol new file mode 100755 index 000000000..b8791ed9e --- /dev/null +++ b/contracts/FtmFeed.sol @@ -0,0 +1,33 @@ +//SPDX-License-Identifier: Unlicense + +pragma solidity ^0.5.16; + +import "./SafeMath.sol"; + +interface IFeed { + function decimals() external view returns (uint8); + function latestAnswer() external view returns (uint); +} + +contract FtmFeed is IFeed { + using SafeMath for uint; + + IFeed public ftmFeed; + IFeed public ethFeed; + + constructor(IFeed _ftmFeed, IFeed _ethFeed) public { + ftmFeed = _ftmFeed; + ethFeed = _ethFeed; + } + + function decimals() public view returns (uint8) { + return 18; + } + + function latestAnswer() public view returns (uint) { + uint ftmEthPrice = ftmFeed.latestAnswer(); + return ftmEthPrice + .mul(ethFeed.latestAnswer()) + .div(10**uint256(ethFeed.decimals())); + } +} diff --git a/deploy/35_ftmFeed.js b/deploy/35_ftmFeed.js new file mode 100644 index 000000000..7048279aa --- /dev/null +++ b/deploy/35_ftmFeed.js @@ -0,0 +1,15 @@ +module.exports = async ({ + deployments, + getNamedAccounts + }) => { + console.log("35. Deploy Ftm Feed") + const {deploy} = deployments; + const {deployer} = await getNamedAccounts(); + + await deploy('FtmFeed', { + from: deployer + }); + + }; + + module.exports.tags = ['FtmFeed']; \ No newline at end of file From a21d9283b2e3613e0277c714aa47522e2644942d Mon Sep 17 00:00:00 2001 From: n3bs Date: Wed, 23 Mar 2022 07:20:08 -0500 Subject: [PATCH 2/3] Fix deployment script, rinkeby deployment artifacts --- contracts/FtmFeed.sol | 2 +- deploy/35_ftmFeed.js | 9 +- deployments/rinkeby/FtmFeed.json | 139 +++++++++++++ .../171aa0e285966923bd7e6058afec666b.json | 185 ++++++++++++++++++ hardhat.config.js | 6 +- 5 files changed, 336 insertions(+), 5 deletions(-) create mode 100644 deployments/rinkeby/FtmFeed.json create mode 100644 deployments/rinkeby/solcInputs/171aa0e285966923bd7e6058afec666b.json diff --git a/contracts/FtmFeed.sol b/contracts/FtmFeed.sol index b8791ed9e..6dccda7e2 100755 --- a/contracts/FtmFeed.sol +++ b/contracts/FtmFeed.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: Unlicense +//SPDX-License-Identifier: None pragma solidity ^0.5.16; diff --git a/deploy/35_ftmFeed.js b/deploy/35_ftmFeed.js index 7048279aa..72c4bac8d 100644 --- a/deploy/35_ftmFeed.js +++ b/deploy/35_ftmFeed.js @@ -4,12 +4,15 @@ module.exports = async ({ }) => { console.log("35. Deploy Ftm Feed") const {deploy} = deployments; - const {deployer} = await getNamedAccounts(); + const {deployer, ftmFeed, ethFeed} = await getNamedAccounts(); await deploy('FtmFeed', { - from: deployer + from: deployer, + args:[ + ftmFeed, + ethFeed + ] }); - }; module.exports.tags = ['FtmFeed']; \ No newline at end of file diff --git a/deployments/rinkeby/FtmFeed.json b/deployments/rinkeby/FtmFeed.json new file mode 100644 index 000000000..bdc38d8da --- /dev/null +++ b/deployments/rinkeby/FtmFeed.json @@ -0,0 +1,139 @@ +{ + "address": "0x492f33D19687CeAedC88aa15d9e511644DC19847", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IFeed", + "name": "_ftmFeed", + "type": "address" + }, + { + "internalType": "contract IFeed", + "name": "_ethFeed", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ethFeed", + "outputs": [ + { + "internalType": "contract IFeed", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ftmFeed", + "outputs": [ + { + "internalType": "contract IFeed", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "latestAnswer", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xbeb6ff5c2e3233cac261a5b91824d9da2c12f85b9a8b0adbc06f7e4212bf8ca8", + "receipt": { + "to": null, + "from": "0xfEEB7b1bc8229617e4fd1C431AB2E26aA0e5877D", + "contractAddress": "0x492f33D19687CeAedC88aa15d9e511644DC19847", + "transactionIndex": 15, + "gasUsed": "317858", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb05aaf69798a3344093e066de12d4ef4a60af54bb7055b0e53af84bc51cfd14c", + "transactionHash": "0xbeb6ff5c2e3233cac261a5b91824d9da2c12f85b9a8b0adbc06f7e4212bf8ca8", + "logs": [], + "blockNumber": 10376491, + "cumulativeGasUsed": "7266590", + "status": 1, + "byzantium": true + }, + "args": [ + "0xc751E86208F0F8aF2d5CD0e29716cA7AD98B5eF5", + "0x8A753747A1Fa494EC906cE90E9f37563A8AF630e" + ], + "solcInputHash": "171aa0e285966923bd7e6058afec666b", + "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"_ftmFeed\",\"type\":\"address\"},{\"internalType\":\"contract IFeed\",\"name\":\"_ethFeed\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ethFeed\",\"outputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ftmFeed\",\"outputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"latestAnswer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/FtmFeed.sol\":\"FtmFeed\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/FtmFeed.sol\":{\"content\":\"//SPDX-License-Identifier: None\\r\\n\\r\\npragma solidity ^0.5.16;\\r\\n\\r\\nimport \\\"./SafeMath.sol\\\";\\r\\n\\r\\ninterface IFeed {\\r\\n function decimals() external view returns (uint8);\\r\\n function latestAnswer() external view returns (uint);\\r\\n}\\r\\n\\r\\ncontract FtmFeed is IFeed {\\r\\n using SafeMath for uint;\\r\\n\\r\\n IFeed public ftmFeed;\\r\\n IFeed public ethFeed;\\r\\n\\r\\n constructor(IFeed _ftmFeed, IFeed _ethFeed) public {\\r\\n ftmFeed = _ftmFeed;\\r\\n ethFeed = _ethFeed;\\r\\n }\\r\\n\\r\\n function decimals() public view returns (uint8) {\\r\\n return 18;\\r\\n }\\r\\n\\r\\n function latestAnswer() public view returns (uint) {\\r\\n uint ftmEthPrice = ftmFeed.latestAnswer();\\r\\n return ftmEthPrice\\r\\n .mul(ethFeed.latestAnswer())\\r\\n .div(10**uint256(ethFeed.decimals()));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7bcc137f3e4e9db8bfb7e953af98304eff47b67ad45be4a91eed6bccfd1a12dc\"},\"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\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161046c38038061046c8339818101604052604081101561003357600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b031991821617909155600180549390921692169190911790556103f28061007a6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063192ad6c014610051578063313ce5671461007557806350d25bcd146100935780635e19d05c146100ad575b600080fd5b6100596100b5565b604080516001600160a01b039092168252519081900360200190f35b61007d6100c4565b6040805160ff9092168252519081900360200190f35b61009b6100c9565b60408051918252519081900360200190f35b61005961024c565b6000546001600160a01b031681565b601290565b60008054604080516350d25bcd60e01b8152905183926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561010e57600080fd5b505afa158015610122573d6000803e3d6000fd5b505050506040513d602081101561013857600080fd5b50516001546040805163313ce56760e01b81529051929350610246926001600160a01b039092169163313ce56791600480820192602092909190829003018186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d60208110156101b057600080fd5b5051600154604080516350d25bcd60e01b8152905160ff909316600a0a9261023a926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561020157600080fd5b505afa158015610215573d6000803e3d6000fd5b505050506040513d602081101561022b57600080fd5b5051849063ffffffff61025b16565b9063ffffffff6102bd16565b91505090565b6001546001600160a01b031681565b60008261026a575060006102b7565b8282028284828161027757fe5b04146102b45760405162461bcd60e51b815260040180806020018281038252602181526020018061039d6021913960400191505060405180910390fd5b90505b92915050565b60006102b483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836103865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561034b578181015183820152602001610333565b50505050905090810190601f1680156103785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161039257fe5b049594505050505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a72315820a5b6384b7cdae8be630ce7f2a291419af18563aafcf3103cac80173257f85de864736f6c63430005100032", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063192ad6c014610051578063313ce5671461007557806350d25bcd146100935780635e19d05c146100ad575b600080fd5b6100596100b5565b604080516001600160a01b039092168252519081900360200190f35b61007d6100c4565b6040805160ff9092168252519081900360200190f35b61009b6100c9565b60408051918252519081900360200190f35b61005961024c565b6000546001600160a01b031681565b601290565b60008054604080516350d25bcd60e01b8152905183926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561010e57600080fd5b505afa158015610122573d6000803e3d6000fd5b505050506040513d602081101561013857600080fd5b50516001546040805163313ce56760e01b81529051929350610246926001600160a01b039092169163313ce56791600480820192602092909190829003018186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d60208110156101b057600080fd5b5051600154604080516350d25bcd60e01b8152905160ff909316600a0a9261023a926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561020157600080fd5b505afa158015610215573d6000803e3d6000fd5b505050506040513d602081101561022b57600080fd5b5051849063ffffffff61025b16565b9063ffffffff6102bd16565b91505090565b6001546001600160a01b031681565b60008261026a575060006102b7565b8282028284828161027757fe5b04146102b45760405162461bcd60e51b815260040180806020018281038252602181526020018061039d6021913960400191505060405180910390fd5b90505b92915050565b60006102b483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836103865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561034b578181015183820152602001610333565b50505050905090810190601f1680156103785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161039257fe5b049594505050505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a72315820a5b6384b7cdae8be630ce7f2a291419af18563aafcf3103cac80173257f85de864736f6c63430005100032", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + }, + "storageLayout": { + "storage": [ + { + "astId": 33267, + "contract": "contracts/FtmFeed.sol:FtmFeed", + "label": "ftmFeed", + "offset": 0, + "slot": "0", + "type": "t_contract(IFeed)33260" + }, + { + "astId": 33269, + "contract": "contracts/FtmFeed.sol:FtmFeed", + "label": "ethFeed", + "offset": 0, + "slot": "1", + "type": "t_contract(IFeed)33260" + } + ], + "types": { + "t_contract(IFeed)33260": { + "encoding": "inplace", + "label": "contract IFeed", + "numberOfBytes": "20" + } + } + } +} \ No newline at end of file diff --git a/deployments/rinkeby/solcInputs/171aa0e285966923bd7e6058afec666b.json b/deployments/rinkeby/solcInputs/171aa0e285966923bd7e6058afec666b.json new file mode 100644 index 000000000..3b6e248cc --- /dev/null +++ b/deployments/rinkeby/solcInputs/171aa0e285966923bd7e6058afec666b.json @@ -0,0 +1,185 @@ +{ + "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/FtmFeed.sol": { + "content": "//SPDX-License-Identifier: None\r\n\r\npragma solidity ^0.5.16;\r\n\r\nimport \"./SafeMath.sol\";\r\n\r\ninterface IFeed {\r\n function decimals() external view returns (uint8);\r\n function latestAnswer() external view returns (uint);\r\n}\r\n\r\ncontract FtmFeed is IFeed {\r\n using SafeMath for uint;\r\n\r\n IFeed public ftmFeed;\r\n IFeed public ethFeed;\r\n\r\n constructor(IFeed _ftmFeed, IFeed _ethFeed) public {\r\n ftmFeed = _ftmFeed;\r\n ethFeed = _ethFeed;\r\n }\r\n\r\n function decimals() public view returns (uint8) {\r\n return 18;\r\n }\r\n\r\n function latestAnswer() public view returns (uint) {\r\n uint ftmEthPrice = ftmFeed.latestAnswer();\r\n return ftmEthPrice\r\n .mul(ethFeed.latestAnswer())\r\n .div(10**uint256(ethFeed.decimals()));\r\n }\r\n}\r\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 b49777883..3950bf285 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -87,7 +87,11 @@ module.exports = { }, stethEthFeed: { 1:"0xAb55Bf4DfBf469ebfe082b7872557D1F87692Fe6" - }, + }, + ftmFeed: { + 1:"0x2de7e4a9488488e0058b95854cc2f7955b35dc9b", + 4:"0xc751E86208F0F8aF2d5CD0e29716cA7AD98B5eF5" + }, deployer:{ default:0 }, From bece10c1a364e7552045bc0786b2499c9dfb66db Mon Sep 17 00:00:00 2001 From: n3bs Date: Wed, 23 Mar 2022 07:42:51 -0500 Subject: [PATCH 3/3] FtmFeed Mainnet deployment artifacts --- deploy/35_ftmFeed.js | 4 +- deployments/mainnet/FtmFeed.json | 139 +++++++++++++ .../171aa0e285966923bd7e6058afec666b.json | 185 ++++++++++++++++++ hardhat.config.js | 2 +- 4 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 deployments/mainnet/FtmFeed.json create mode 100644 deployments/mainnet/solcInputs/171aa0e285966923bd7e6058afec666b.json diff --git a/deploy/35_ftmFeed.js b/deploy/35_ftmFeed.js index 72c4bac8d..871a83990 100644 --- a/deploy/35_ftmFeed.js +++ b/deploy/35_ftmFeed.js @@ -4,12 +4,12 @@ module.exports = async ({ }) => { console.log("35. Deploy Ftm Feed") const {deploy} = deployments; - const {deployer, ftmFeed, ethFeed} = await getNamedAccounts(); + const {deployer, ftmEthFeed, ethFeed} = await getNamedAccounts(); await deploy('FtmFeed', { from: deployer, args:[ - ftmFeed, + ftmEthFeed, ethFeed ] }); diff --git a/deployments/mainnet/FtmFeed.json b/deployments/mainnet/FtmFeed.json new file mode 100644 index 000000000..ef20aaf5c --- /dev/null +++ b/deployments/mainnet/FtmFeed.json @@ -0,0 +1,139 @@ +{ + "address": "0x9bC8c0FaA1d450e9E0e4f08c198f0b0dab37478f", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IFeed", + "name": "_ftmFeed", + "type": "address" + }, + { + "internalType": "contract IFeed", + "name": "_ethFeed", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ethFeed", + "outputs": [ + { + "internalType": "contract IFeed", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ftmFeed", + "outputs": [ + { + "internalType": "contract IFeed", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "latestAnswer", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xf741822117e097a1283fdd97c131191aa0844f1b3a874cd146c5032fb16bda0b", + "receipt": { + "to": null, + "from": "0xfEEB7b1bc8229617e4fd1C431AB2E26aA0e5877D", + "contractAddress": "0x9bC8c0FaA1d450e9E0e4f08c198f0b0dab37478f", + "transactionIndex": 488, + "gasUsed": "317858", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x9ef18bc6c9598013acac77b7cbd71ccb1326d41c714ba7496fb4c23459e477ed", + "transactionHash": "0xf741822117e097a1283fdd97c131191aa0844f1b3a874cd146c5032fb16bda0b", + "logs": [], + "blockNumber": 14442586, + "cumulativeGasUsed": "26048307", + "status": 1, + "byzantium": true + }, + "args": [ + "0x2DE7E4a9488488e0058B95854CC2f7955B35dC9b", + "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" + ], + "solcInputHash": "171aa0e285966923bd7e6058afec666b", + "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"_ftmFeed\",\"type\":\"address\"},{\"internalType\":\"contract IFeed\",\"name\":\"_ethFeed\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ethFeed\",\"outputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ftmFeed\",\"outputs\":[{\"internalType\":\"contract IFeed\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"latestAnswer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/FtmFeed.sol\":\"FtmFeed\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/FtmFeed.sol\":{\"content\":\"//SPDX-License-Identifier: None\\r\\n\\r\\npragma solidity ^0.5.16;\\r\\n\\r\\nimport \\\"./SafeMath.sol\\\";\\r\\n\\r\\ninterface IFeed {\\r\\n function decimals() external view returns (uint8);\\r\\n function latestAnswer() external view returns (uint);\\r\\n}\\r\\n\\r\\ncontract FtmFeed is IFeed {\\r\\n using SafeMath for uint;\\r\\n\\r\\n IFeed public ftmFeed;\\r\\n IFeed public ethFeed;\\r\\n\\r\\n constructor(IFeed _ftmFeed, IFeed _ethFeed) public {\\r\\n ftmFeed = _ftmFeed;\\r\\n ethFeed = _ethFeed;\\r\\n }\\r\\n\\r\\n function decimals() public view returns (uint8) {\\r\\n return 18;\\r\\n }\\r\\n\\r\\n function latestAnswer() public view returns (uint) {\\r\\n uint ftmEthPrice = ftmFeed.latestAnswer();\\r\\n return ftmEthPrice\\r\\n .mul(ethFeed.latestAnswer())\\r\\n .div(10**uint256(ethFeed.decimals()));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7bcc137f3e4e9db8bfb7e953af98304eff47b67ad45be4a91eed6bccfd1a12dc\"},\"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\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161046c38038061046c8339818101604052604081101561003357600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b031991821617909155600180549390921692169190911790556103f28061007a6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063192ad6c014610051578063313ce5671461007557806350d25bcd146100935780635e19d05c146100ad575b600080fd5b6100596100b5565b604080516001600160a01b039092168252519081900360200190f35b61007d6100c4565b6040805160ff9092168252519081900360200190f35b61009b6100c9565b60408051918252519081900360200190f35b61005961024c565b6000546001600160a01b031681565b601290565b60008054604080516350d25bcd60e01b8152905183926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561010e57600080fd5b505afa158015610122573d6000803e3d6000fd5b505050506040513d602081101561013857600080fd5b50516001546040805163313ce56760e01b81529051929350610246926001600160a01b039092169163313ce56791600480820192602092909190829003018186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d60208110156101b057600080fd5b5051600154604080516350d25bcd60e01b8152905160ff909316600a0a9261023a926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561020157600080fd5b505afa158015610215573d6000803e3d6000fd5b505050506040513d602081101561022b57600080fd5b5051849063ffffffff61025b16565b9063ffffffff6102bd16565b91505090565b6001546001600160a01b031681565b60008261026a575060006102b7565b8282028284828161027757fe5b04146102b45760405162461bcd60e51b815260040180806020018281038252602181526020018061039d6021913960400191505060405180910390fd5b90505b92915050565b60006102b483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836103865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561034b578181015183820152602001610333565b50505050905090810190601f1680156103785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161039257fe5b049594505050505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a72315820a5b6384b7cdae8be630ce7f2a291419af18563aafcf3103cac80173257f85de864736f6c63430005100032", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063192ad6c014610051578063313ce5671461007557806350d25bcd146100935780635e19d05c146100ad575b600080fd5b6100596100b5565b604080516001600160a01b039092168252519081900360200190f35b61007d6100c4565b6040805160ff9092168252519081900360200190f35b61009b6100c9565b60408051918252519081900360200190f35b61005961024c565b6000546001600160a01b031681565b601290565b60008054604080516350d25bcd60e01b8152905183926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561010e57600080fd5b505afa158015610122573d6000803e3d6000fd5b505050506040513d602081101561013857600080fd5b50516001546040805163313ce56760e01b81529051929350610246926001600160a01b039092169163313ce56791600480820192602092909190829003018186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d60208110156101b057600080fd5b5051600154604080516350d25bcd60e01b8152905160ff909316600a0a9261023a926001600160a01b0316916350d25bcd916004808301926020929190829003018186803b15801561020157600080fd5b505afa158015610215573d6000803e3d6000fd5b505050506040513d602081101561022b57600080fd5b5051849063ffffffff61025b16565b9063ffffffff6102bd16565b91505090565b6001546001600160a01b031681565b60008261026a575060006102b7565b8282028284828161027757fe5b04146102b45760405162461bcd60e51b815260040180806020018281038252602181526020018061039d6021913960400191505060405180910390fd5b90505b92915050565b60006102b483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250600081836103865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561034b578181015183820152602001610333565b50505050905090810190601f1680156103785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161039257fe5b049594505050505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a72315820a5b6384b7cdae8be630ce7f2a291419af18563aafcf3103cac80173257f85de864736f6c63430005100032", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + }, + "storageLayout": { + "storage": [ + { + "astId": 33267, + "contract": "contracts/FtmFeed.sol:FtmFeed", + "label": "ftmFeed", + "offset": 0, + "slot": "0", + "type": "t_contract(IFeed)33260" + }, + { + "astId": 33269, + "contract": "contracts/FtmFeed.sol:FtmFeed", + "label": "ethFeed", + "offset": 0, + "slot": "1", + "type": "t_contract(IFeed)33260" + } + ], + "types": { + "t_contract(IFeed)33260": { + "encoding": "inplace", + "label": "contract IFeed", + "numberOfBytes": "20" + } + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/solcInputs/171aa0e285966923bd7e6058afec666b.json b/deployments/mainnet/solcInputs/171aa0e285966923bd7e6058afec666b.json new file mode 100644 index 000000000..3b6e248cc --- /dev/null +++ b/deployments/mainnet/solcInputs/171aa0e285966923bd7e6058afec666b.json @@ -0,0 +1,185 @@ +{ + "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/FtmFeed.sol": { + "content": "//SPDX-License-Identifier: None\r\n\r\npragma solidity ^0.5.16;\r\n\r\nimport \"./SafeMath.sol\";\r\n\r\ninterface IFeed {\r\n function decimals() external view returns (uint8);\r\n function latestAnswer() external view returns (uint);\r\n}\r\n\r\ncontract FtmFeed is IFeed {\r\n using SafeMath for uint;\r\n\r\n IFeed public ftmFeed;\r\n IFeed public ethFeed;\r\n\r\n constructor(IFeed _ftmFeed, IFeed _ethFeed) public {\r\n ftmFeed = _ftmFeed;\r\n ethFeed = _ethFeed;\r\n }\r\n\r\n function decimals() public view returns (uint8) {\r\n return 18;\r\n }\r\n\r\n function latestAnswer() public view returns (uint) {\r\n uint ftmEthPrice = ftmFeed.latestAnswer();\r\n return ftmEthPrice\r\n .mul(ethFeed.latestAnswer())\r\n .div(10**uint256(ethFeed.decimals()));\r\n }\r\n}\r\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 3950bf285..987924c2d 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -88,7 +88,7 @@ module.exports = { stethEthFeed: { 1:"0xAb55Bf4DfBf469ebfe082b7872557D1F87692Fe6" }, - ftmFeed: { + ftmEthFeed: { 1:"0x2de7e4a9488488e0058b95854cc2f7955b35dc9b", 4:"0xc751E86208F0F8aF2d5CD0e29716cA7AD98B5eF5" },